public class ORM {

  private ORM() {}

  /**
   * XML file namespace
   */
  public static final String TAG_NAMESPACE = "namespace";
  /**
   * XML file orm id
   */
  public static final String TAG_ORM_ID = "id";

  /**
   * XML file orm db collection
   */
  public static final String TAG_DB_COLLECTION = "collection";

  /**
   * XML file 'column' tag
   */
  public static final String TAG_CLUMN = "column";

  /**
   * XML file 'name' tag
   */
  public static final String TAG_NAME = "name";

  /**
   * XML file 'operate' tag
   */
  public static final String TAG_OPERATE = "operate";

  /**
   * XML file 'value' tag
   */
  public static final String TAG_VALUE = "value";

  /**
   * XML file 'type' tag
   */
  public static final String TAG_TYPE = "type";

  /**
   * XML file 'ignoreNull' tag
   */
  public static final String TAG_IGNORE_NULL = "ignoreNull";
  /**
   * XML file 'ignoreEmpty' tag
   */
  public static final String TAG_IGNORE_EMPTY = "ignoreEmpty";
  /**
   * XML file orm class tag
   */
  public static final String ORM_CLASS = "class";

  /**
   * XML file orm extends tag
   */
  public static final String ORM_EXTENDS = "extends";

  /**
   * XML file orm mapping tag
   */
  public static final String ORM_MAPPING = "mapping";

  /**
   * XML file node 'query'
   */
  public static final String NODE_QUERY = "query";

  /**
   * XML file node 'field'
   */
  public static final String NODE_FIELD = "field";

  /**
   * XML file child node 'value'
   */
  public static final String NODE_CHILD_NODE = "value";

  /**
   * XML file node 'order'
   */
  public static final String NODE_ORDER = "order";

  /**
   * XML file node 'action'
   */
  public static final String NODE_ACTION = "action";

  /**
   * XML file node 'document'
   */
  public static final String NODE_DOCUMENT = "document";

  /**
   * XML file node 'selectKey'
   */
  public static final String NODE_SELECTKEY = "selectKey";

  /**
   * XML file node 'key'
   */
  public static final String NODE_KEY = "key";

  /**
   * XML file node 'keyf'
   */
  public static final String NODE_KEY_FUNCTION = "keyf";

  /**
   * XML file node 'initial'
   */
  public static final String NODE_INITIAL = "initial";

  /**
   * XML file node 'condition'
   */
  public static final String NODE_CONDITION = "condition";

  /**
   * XML file node 'map'
   */
  public static final String NODE_MAP = "map";
  
  /**
   * XML file node 'reduce'
   */
  public static final String NODE_REDUCE = "reduce";

  /**
   * XML file node 'finalize'
   */
  public static final String NODE_FINALIZE = "finalize";

  /**
   * XML file node 'function'
   */
  public static final String NODE_FUNCTION = "function";

  /**
   * XML file node 'pipeline'
   */
  public static final String NODE_PIPELINE = "pipeline";
  /**
   * XML file script params tag start
   */
  public static final String LABEL_SCRIPT_START = "${";
  /**
   * XML file script params tag end
   */
  public static final String LABEL_SCRIPT_END = "}";
  /**
   * XML file 'value' label. Example <property column="name" value="${value}" />
   */
  public static final String LABEL_VALUE = LABEL_SCRIPT_START + "value" + LABEL_SCRIPT_END;
}
 public class StatementException extends RuntimeException {

  private static final long serialVersionUID = 3988706952509457604L;

  private static final Logger logger = LoggerFactory.getLogger(StatementException.class);

  private String message;

  public StatementException(String message) {
    super(message);
    this.message = message;
    logger.error("Mongodb orm statement error. Cause:  " + message);
  }

  public StatementException(String message, Throwable e) {
    super(message, e);
    this.message = message;
    logger.error("Mongodb orm statement error. Cause: " + message, e);
  }

  @Override
  public String getLocalizedMessage() {
    return message;
  }

}
 public class Dynamic {

  private Function function;
  private FunctionData data;

  public void addFunction(Function function, FunctionData data) {
    this.function = function;
    this.data = data;
  }

  public Object parser(Object target) throws MongoORMException {
    return function.parser(data, target);
  }

  public Function getFunction() {
    return function;
  }

  public FunctionData getData() {
    return data;
  }

}
 public class DynamicFactory {

  private DynamicFactory() {}

  public static Dynamic builder(Node node, Class<?> clazz) {
    String name = node.getNodeName();
    return Creator.valueOf(name).create(node, clazz);
  }

  private static enum Creator {
    list {
      @Override
      Dynamic create(Node node, Class<?> clazz) {
        Dynamic dynamic = new Dynamic();
        new ListFunction().init(node, clazz, dynamic);
        return dynamic;
      }
    },
    text {
      @Override
      Dynamic create(Node node, Class<?> clazz) {
        Dynamic dynamic = new Dynamic();
        new TextFunction().init(node, clazz, dynamic);
        return dynamic;
      }
    },
    script {
      @Override
      Dynamic create(Node node, Class<?> clazz) {
        Dynamic dynamic = new Dynamic();
        new ScriptFunction().init(node, clazz, dynamic);
        return dynamic;
      }
    };
    abstract Dynamic create(Node node, Class<?> clazz);
  }

}
 public interface Config extends Serializable {
}
 public enum ColumnType {
  
  string("string"), 
  _number("number"), 
  _boolean("boolean"),
  _double("double"), 
  objectid("objectid"), 
  date("date"),
  regex("regex"),
  _byte("byte");
  
  private String type;
  
  public static ColumnType fromType(String type) {
    if(StringUtils.isBlank(type)) {
      return null;
    }
    
    for(ColumnType ct : values()) {
      if(ct.type.equals(type)) {
        return ct;
      }
    }
    throw new StatementException("Unknow column type '"+type+"'");
  }
  
  private ColumnType(String type) {
    this.type = type;
  }

  public String getType() {
    return type;
  }
  
}
 public class Entry implements Serializable {

  private static final long serialVersionUID = 2410570509734423022L;

  /**
   * Database column.
   */
  private String column;
  /**
   * Parameter name or entry field.
   */
  private String name;
  /**
   * Default value.
   */
  private Object value;
  /**
   * Resovler a available column type for mongodb.
   */
  private ColumnHandler<?> columnHandler;
  /**
   * Operate tag.
   * <p>
   * '$set', '$lt', '$elementMatch'
   * </p>
   */
  private String operate;
  /**
   * Whether to ignore null.
   */
  private Boolean ignoreNull;
  /**
   * Whether to ignore empty.
   */
  private Boolean ignoreEmpty;
  /**
   * Dynamic node
   */
  private Dynamic dynamic;
  /**
   * Child nodes.
   */
  private List<NodeEntry> nodes;

  public String getColumn() {
    return column;
  }

  public void setColumn(String column) {
    this.column = column;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Object getValue() {
    return value;
  }

  public void setValue(Object value) {
    this.value = value;
  }

  public ColumnHandler<?> getColumnHandler() {
    return columnHandler;
  }

  public void setColumnHandler(ColumnHandler<?> columnHandler) {
    this.columnHandler = columnHandler;
  }

  public String getOperate() {
    return operate;
  }

  public void setOperate(String operate) {
    this.operate = operate;
  }

  public boolean isIgnoreNull() {
    return (ignoreNull==null) ? false: ignoreNull;
  }
  
  public void setIgnoreNull(Boolean ignoreNull) {
    this.ignoreNull = ignoreNull;
  }

  public boolean isIgnoreEmpty() {
    return (ignoreEmpty==null) ? false: ignoreEmpty;
  }
  
  public void setIgnoreEmpty(Boolean ignoreEmpty) {
    this.ignoreEmpty = ignoreEmpty;
  }

  public Dynamic getDynamic() {
    return dynamic;
  }

  public void setDynamic(Dynamic dynamic) {
    this.dynamic = dynamic;
  }

  public List<NodeEntry> getNodes() {
    return nodes;
  }

  public void setNodes(List<NodeEntry> nodes) {
    this.nodes = nodes;
  }

  public Entry addNode(NodeEntry node) {
    if (nodes == null) {
      nodes = new ArrayList<NodeEntry>();
    }
    nodes.add(node);
    return this;
  }

}
 public class NodeEntry implements Serializable {

  private static final long serialVersionUID = -6974784211299835940L;

  /**
   * Mapping id.
   */
  private String mappingId;

  /**
   * Node parameter class type.
   */
  private Class<?> clazz;

  /**
   * Node elements mapping entry.
   */
  private List<Entry> nodeMappings;
  
  /**
   * Getting data into, and out of a mapped statement.
   */
  private TypeHandler<?> typeHandler;
  
  /**
   * Mql node executor
   */
  private MqlExecutor<?> executor;
  
  public Object executorNode(String namespace, MqlMapConfiguration configuration, Object target) {
    return executor.parser(namespace, configuration, this, target);
  }
  
  public String getMappingId() {
    return mappingId;
  }

  public void setMappingId(String mappingId) {
    this.mappingId = mappingId;
  }

  public Class<?> getClazz() {
    return clazz;
  }

  public void setClazz(Class<?> clazz) {
    this.clazz = clazz;
  }

  public List<Entry> getNodeMappings() {
    return nodeMappings;
  }

  public void setNodeMappings(List<Entry> nodeMappings) {
    this.nodeMappings = nodeMappings;
  }

  public TypeHandler<?> getTypeHandler() {
    return typeHandler;
  }

  public void setTypeHandler(TypeHandler<?> typeHandler) {
    this.typeHandler = typeHandler;
  }

  public void setExecutor(MqlExecutor<?> executor) {
    this.executor = executor;
  }

}
 public enum Operator {
  
  /**
   * Query and Projection Operators.
   */
  /* Comparison */
  $eq("$eq"),
  $gt("$gt"),
  $gte("$gte"),
  $in("$in"),
  $lt("$lt"),
  $lte("$lte"),
  $ne("$ne"),
  $nin("$nin"),
  /* Logical */
  $and("$and"),
  $not("$not"),
  $nor("$nor"),
  $or("$or"),  
  /* Element */
  $exists("$exists"),
  $type("$type"),
  /* Evaluation */
  $expr("$expr"),
  $jsonSchema("$jsonSchema"),
  $mod("$mod"),
  $regex("$regex"),
  $text("$text"),
  $where("$where"),
  /* Geospatial */
  $geoIntersects("$geoIntersects"),
  $geoWithin("$geoWithin"),
  $near("$near"),
  $nearSphere("$nearSphere"),
  /* Array */
  $all("$all"),
  $elemMatch("$elemMatch"),
  $size("$size"),
  /* Bitwise */
  $bitsAllClear("$bitsAllClear"),
  $bitsAllSet("$bitsAllSet"),
  $bitsAnyClear("$bitsAnyClear"),
  $bitsAnySet("$bitsAnySet"),
  /* Comments */
  $comment("$comment"),
  /* Projection Operators */
  $("$"),
  $meta("$meta"),
  $slice("$slice"),
  
  /**
   * Update Operators.
   */
  /* Fields */
  $currentDate("$currentDate"),
  $inc("$inc"),
  $min("$min"),
  $max("$max"),
  $mul("$mul"),
  $rename("$rename"),
  $set("$set"),
  $setOnInsert("$setOnInsert"),
  $unset("$unset"),
  /* Array */
  $array("$[]"),
  $identifier("^\\$\\[.+\\]$"), // $[<identifier>]
  $addToSet("$addToSet"),
  $pop("$pop"),
  $pull("$pull"),
  $push("$push"),
  $pullAll("$pullAll"),
  /* Modifiers */
  $each("$each"),
  $position("$position"),
  $sort("$sort"),
  /* Bitwise */
  $bit("$bit"),
  
  /**
   * Aggregation Pipeline Stages
   */
  /* Collection Stages */
  $addFields("$addFields"),
  $bucket("$bucket"),
  $bucketAuto("$bucketAuto"),
  $collStats("$collStats"),
  $count("$count"),
  $facet("$facet"),
  $geoNear("$geoNear"),
  $graphLookup("$graphLookup"),
  $group("$group"),
  $indexStats("$indexStats"),
  $limit("$limit"),
  $listSessions("$listSessions"),
  $lookup("$lookup"),
  $match("$match"),
  $out("$out"),
  $project("$project"),
  $redact("$redact"),
  $replaceRoot("$replaceRoot"),
  $sample("$sample"),
  $skip("$skip"),
  $sortByCount("$sortByCount"),
  $unwind("$unwind"),
  /* DB Stages */
  $currentOp("$currentOp"),
  $listLocalSessions("$listLocalSessions"),    
  
  /**
   * Aggregation Pipeline Operators 
   */
  $abs("$abs"),
  $add("$add"),
  $ceil("$ceil"),
  $divide("$divide"),
  $exp("$exp"),
  $floor("$floor"),
  $ln("$ln"),
  $log("$log"),
  $log10("$log10"),
  $multiply("$multiply"),  
  $pow("$pow"),
  $sqrt("$sqrt"),
  $subtract("$subtract"),
  $trunc("$trunc"),
  /* Array Expression Operators */
  $arrayElemAt("$arrayElemAt"),
  $arrayToObject("$arrayToObject"),
  $concatArrays("$concatArrays"),
  $filter("$filter"),
  $indexOfArray("$indexOfArray"),
  $isArray("$isArray"),
  $map("$map"),
  $objectToArray("$objectToArray"),
  $range("$range"),
  $reduce("$reduce"),
  $reverseArray("$reverseArray"),
  $zip("$zip"),
  /* Comparison Expression Operators */
  $cmp("$cmp"),
  /* Conditional Expression Operators */
  $cond("$"),
  $ifNull("$ifNull"),
  $switch("$switch"),
  /* Date Expression Operators */
  $dateFromParts("$dateFromParts"),
  $dateFromString("$dateFromString"),
  $dateToParts("$dateToParts"),
  $dateToString("$dateToString"),
  $dayOfMonth("$dayOfMonth"),
  $dayOfWeek("$dayOfWeek"),
  $dayOfYear("$dayOfYear"),
  $hour("$hour"),
  $isoDayOfWeek("$isoDayOfWeek"),
  $isoWeek("$isoWeek"),
  $isoWeekYear("$isoWeekYear"),
  $millisecond("$millisecond"),
  $minute("$minute"),
  $month("$month"),
  $second("$second"),
  $toDate("$toDate"),
  $week("$week"),
  $year("$year"),
  /* Literal Expression Operator */
  $literal("$literal"),
  /* Object Expression Operators */
  $mergeObjects("$mergeObjects"),
  /* Set Expression Operators */
  $allElementsTrue("$allElementsTrue"),
  $anyElementTrue("$anyElementTrue"),
  $setDifference("$setDifference"),
  $setEquals("$setEquals"),
  $setIntersection("$setIntersection"),
  $setIsSubset("$setIsSubset"),
  $setUnion("$setUnion"),
  /* String Expression Operators */
  $concat("$concat"),
  $indexOfBytes("$indexOfBytes"),
  $indexOfCP("$indexOfCP"),
  $ltrim("$ltrim"),
  $rtrim("$rtrim"),
  $split("$split"),
  $strLenBytes("$strLenBytes"),
  $strLenCP("$strLenCP"),
  $strcasecmp("$strcasecmp"),
  $substr("$substr"),
  $substrBytes("$substrBytes"),
  $substrCP("$substrCP"),
  $toLower("$toLower"),
  $toString("$toString"),
  $trim("$trim"),
  $toUpper("$toUpper"),
  /* Type Expression Operators */
  $convert("$convert"),
  $toBool("$toBool"),
  $toDecimal("$toDecimal"),
  $toDouble("$toDouble"),
  $toInt("$toInt"),
  $toLong("$toLong"),
  $toObjectId("$toObjectId"),
  /* Accumulators ($group) */
  $avg("$avg"),
  $first("$first"),
  $last("$last"),
  $stdDevPop("$stdDevPop"),
  $stdDevSamp("$stdDevSamp"),
  $sum("$sum"),
  /* Variable Expression Operators */
  $let("$let"),
  
  /**
   * Query Modifiers
   */
  /* Operators */
  $explain("$explain"),
  $hint("$hint"),
  $maxScan("$maxScan"),
  $maxTimeMS("$maxTimeMS"),
  $orderby("$orderby"),
  $query("$query"),
  $returnKey("$returnKey"),
  $showDiskLoc("$showDiskLoc"),
  /* Sort Order */
  $natural("$natural"),;
  
  private String opt;
  
  public static String formName(String name) {
    if(name == null) {
      return null;
    }
    
    try {
      return Operator.valueOf(name).getOpt();
    } catch (IllegalArgumentException ex) {
      if (name.equals($array.opt)) {
        return name;
      }
      
      if (name.matches($identifier.opt)) {
        return name;
      }
      throw new StatementException("Error operator const '"+name+"'.");
    }
  }
  
  private Operator(String opt) {
    this.opt = opt;
  }

  public String getOpt() {
    return opt;
  }
}
 public class TypeHandlerFactory {

  private TypeHandlerFactory() {}

  /**
   * Type handler for database columns.
   */
  private static Map<Class<?>, Factory> typeAliases = new HashMap<Class<?>, Factory>();

  private static Map<ColumnType, ColumnHandler<?>> typeHandlers = new HashMap<ColumnType, ColumnHandler<?>>();

  private static Factory defaultHandlerFactory = new Factory() {
    @Override
    public TypeHandler<?> create(Class<?> clazz) {
      return new CustomHandler(clazz);
    }
  };

  static {
    Factory factory;

    factory = new Factory() {
      @Override
      public TypeHandler<Boolean> create(Class<?> clazz) {
        return new BooleanTypeHandler();
      }
    };
    register(Boolean.class, factory);
    register(boolean.class, factory);

    factory = new Factory() {
      @Override
      public TypeHandler<byte[]> create(Class<?> clazz) {
        return new ByteTypeHandler();
      }
    };
    register(Byte.class, factory);
    register(byte.class, factory);

    factory = new Factory() {
      @Override
      public TypeHandler<Short> create(Class<?> clazz) {
        return new ShortTypeHandler();
      }
    };
    register(Short.class, factory);
    register(short.class, factory);

    factory = new Factory() {
      @Override
      public TypeHandler<Integer> create(Class<?> clazz) {
        return new IntegerTypeHandler();
      }
    };
    register(Integer.class, factory);
    register(int.class, factory);

    factory = new Factory() {
      @Override
      public TypeHandler<Long> create(Class<?> clazz) {
        return new LongTypeHandler();
      }
    };
    register(Long.class, factory);
    register(long.class, factory);

    factory = new Factory() {
      @Override
      public TypeHandler<Float> create(Class<?> clazz) {
        return new FloatTypeHandler();
      }
    };
    register(Float.class, factory);
    register(float.class, factory);

    factory = new Factory() {
      @Override
      public TypeHandler<Double> create(Class<?> clazz) {
        return new DoubleTypeHandler();
      }
    };
    register(Double.class, factory);
    register(double.class, factory);

    register(String.class, factory = new Factory() {
      @Override
      public TypeHandler<String> create(Class<?> clazz) {
        return new StringTypeHandler();
      }
    });

    register(BigDecimal.class, factory = new Factory() {
      @Override
      public TypeHandler<BigDecimal> create(Class<?> clazz) {
        return new BigDecimalTypeHandler();
      }
    });

    register(byte[].class, factory = new Factory() {
      @Override
      public TypeHandler<byte[]> create(Class<?> clazz) {
        return new ByteArrayTypeHandler();
      }
    });

    register(Date.class, factory = new Factory() {
      @Override
      public TypeHandler<Date> create(Class<?> clazz) {
        return new DateTypeHandler();
      }
    });

    register(List.class, factory = new Factory() {
      @Override
      public TypeHandler<List<?>> create(Class<?> clazz) {
        return new ListTypeHandler(clazz);
      }
    });
    
    register(Set.class, factory = new Factory() {
      @Override
      public TypeHandler<Set<?>> create(Class<?> clazz) {
        return new SetTypeHandler(clazz);
      }
    });

    register(Map.class, factory = new Factory() {
      @Override
      public TypeHandler<Map<Object, Object>> create(Class<?> clazz) {
        return new MapTypeHandler();
      }
    });

    register(Iterator.class, factory = new Factory() {
      @Override
      public TypeHandler<Iterator<?>> create(Class<?> clazz) {
        return new IteratorTypeHandler();
      }
    });

    register(Enum.class, factory = new Factory() {
      @Override
      public TypeHandler<Enum<?>> create(Class<?> clazz) {
        return new EnumTypeHandler(clazz);
      }
    });

    putTypeAlias(ColumnType.string, new StringTypeHandler());
    putTypeAlias(ColumnType._number, new LongTypeHandler());
    putTypeAlias(ColumnType._double, new DoubleTypeHandler());
    putTypeAlias(ColumnType._boolean, new BooleanTypeHandler());
    putTypeAlias(ColumnType.regex, new RegexTypeHandler());
    putTypeAlias(ColumnType.objectid, new ObjectIdTypeHandler());

    // Temporarily does not support
    putTypeAlias(ColumnType._byte, new ByteTypeHandler());
    putTypeAlias(ColumnType.date, new DateTypeHandler());
    
  }

  public static ColumnHandler<?> getColumnHandler(ColumnType type) {
    if (type == null) {
      return null;
    }

    ColumnHandler<?> handler = typeHandlers.get(type);
    if (handler == null) {
      throw new StatementException("Error type const for get hander '" + type + "'.");
    }
    return handler;
  }

  public static TypeHandler<?> getTypeHandler(Class<?> clazz) {
    if (clazz == null) {
      return null;
    }

    Factory factory = findFactory(clazz);
    if (factory == null) {
      factory = defaultHandlerFactory;
    }
    return factory.create(clazz);
  }

  public static boolean has(Class<?> clazz) {
    if (clazz == null) {
      return false;
    }
    
    if(findFactory(clazz) != null) {
      return true;
    }
    return false;
  }

  public static boolean hasColumnType(ColumnType type) {
    if (type == null) {
      return false;
    }
    return typeHandlers.containsKey(type);
  }

  /**
   * Regist type handler.
   */
  private static void register(Class<?> clazz, Factory factory) {
    typeAliases.put(clazz, factory);
  }

  /**
   * Resolve type alias type handler.
   */
  private static void putTypeAlias(ColumnType columnType, ColumnHandler<?> handler) {
    typeHandlers.put(columnType, handler);
  }
  
  private static Factory findFactory(Class<?> clazz) {
    Factory factory = typeAliases.get(clazz);
    if(factory != null) {
      return factory;
    }
    
    for(Map.Entry<Class<?>, Factory> entry: typeAliases.entrySet()) {
      if(entry.getKey().isAssignableFrom(clazz)) {
        return entry.getValue();
      }
    }
    return null;
  }

  private interface Factory {
    public TypeHandler<?> create(Class<?> clazz);
  }
  
}
 public interface MqlExecutor<T> {
    
    public T parser(String namespace, MqlMapConfiguration configuration, NodeEntry entry, Object target) throws MongoORMException;
    
    /**
     * SqlExecutor callback 
     * @author yy
     */
    public static interface CallBack<T> {
        T callback(String namespace, MqlMapConfiguration configuration, NodeEntry entry, Object target) throws MongoORMException;
    }
    
} public class ActionExecutor implements MqlExecutor<Map<String, Object>> {

  @Override
  public Map<String, Object> parser(String namespace, MqlMapConfiguration configuration, NodeEntry entry, Object target) throws MongoORMException {
    List<Entry> entrys = entry.getNodeMappings();
    TypeHandler<?> typeHandler = entry.getTypeHandler();
    String mappingId = entry.getMappingId();
    if (mappingId != null) {
      MappingConfig mapping = (MappingConfig) configuration.getMapping(namespace, mappingId);
      entrys = mapping.getNodes();
      typeHandler = mapping.getTypeHandler();
    }

    OptSet optSet = new OptSet();
    Map<String, Object> action = new LinkedHashMap<String, Object>();
    for (Entry ety : entrys) {
      StrategyContext context = new StrategyContext(ety, target, callback);
      context.setTypeHandler(typeHandler);
      
      new StrategyChain().doStrategy(namespace, configuration, context);

      Object value = context.getValue();
      if(!ObjectUtils.checkValueNull(value, ety)) {
        String column = ety.getColumn();
        String name = ety.getName();
        String operate = ety.getOperate();
        
        if(operate != null) {
          if(name != null) {
            action.put(operate, value);
          } else {
            optSet.addOpt(operate, column, value);
          }
        } else {
          action.put(column, value);
        }
      }
    }
    optSet.excute(action);
    return action;
  }
  
  CallBack<Map<String, Object>> callback = new CallBack<Map<String, Object>>() {
    @Override
    public Map<String, Object> callback(String namespace, MqlMapConfiguration configuration, NodeEntry entry, Object target) throws MongoORMException {
      return parser(namespace, configuration, entry, target);
    }
  };

  class OptSet {
    Map<String, Map<String, Object>> operateSet = new LinkedHashMap<String, Map<String, Object>>();

    void addOpt(String opt, String column, Object value) {
      Map<String, Object> map = operateSet.get(opt);
      if (map == null) {
        map = new HashMap<String, Object>();
        map.put(column, value);
        operateSet.put(opt, map);
      } else {
        map.put(column, value);
      }
    }

    OptSet excute(Map<String, Object> action) {
      for (String opt : operateSet.keySet()) {
        Map<String, Object> map = operateSet.get(opt);
        Map<String, Object> value = new HashMap<String, Object>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
          value.put(entry.getKey(), entry.getValue());
        }
        action.put(opt, value);
      }
      return this;
    }
  }

}
 public class FieldExecutor implements MqlExecutor<Map<String, Object>> {

  @Override
  public Map<String, Object> parser(String namespace, MqlMapConfiguration configuration, NodeEntry entry, Object target) throws MongoORMException {
    List<Entry> entrys = entry.getNodeMappings();
    String mappingId = entry.getMappingId();
    if (mappingId != null) {
      MappingConfig mapping = (MappingConfig) configuration.getMapping(namespace, mappingId);
      entrys = mapping.getNodes();
    }
    
    Map<String, Object> field = new LinkedHashMap<String, Object>();
    for (Entry ety : entrys) {
// parent node include children fields
//      List<NodeEntry> nodes = ety.getNodes();
//      if(!ObjectUtils.isEmpty(nodes)) {
//        for(NodeEntry node : nodes) {
//          field.putAll(callback.callBack(configuration, node, target));
//        }
//      }
      field.put(ety.getColumn(), 1);
    }
    return field;
  }

  CallBack<Map<String, Object>> callback = new CallBack<Map<String, Object>>() {
    @Override
    public Map<String, Object> callback(String namespace, MqlMapConfiguration configuration, NodeEntry entry, Object target) throws MongoORMException {
      return parser(namespace, configuration, entry, target);
    }
  };
  
}
 public class  OrderExecutor implements MqlExecutor<Map<String, Object>> {

  @Override
  public Map<String, Object> parser(String namespace, MqlMapConfiguration configuration, NodeEntry entry, Object target) throws MongoORMException {
    List<Entry> entrys = entry.getNodeMappings();
    TypeHandler<?> typeHandler = entry.getTypeHandler();
    String mappingId = entry.getMappingId();
    if (mappingId != null) {
      MappingConfig mapping = (MappingConfig) configuration.getMapping(namespace, mappingId);
      entrys = mapping.getNodes();
      typeHandler = mapping.getTypeHandler();
    }
    
    Map<String, Object> order = new LinkedHashMap<String, Object>();
    for (Entry ety : entrys) {
      StrategyContext context = new StrategyContext(ety, target, callback);
      context.setTypeHandler(typeHandler);

      new StrategyChain().doStrategy(namespace, configuration, context);

      Object value = context.getValue();
      if(!ObjectUtils.checkValueNull(value, ety)) {
        String column = ety.getColumn();
        order.put(column, value);
      }
    }
    return order;
  }
  
  CallBack<Map<String, Object>> callback = new CallBack<Map<String, Object>>() {
    @Override
    public Map<String, Object> callback(String namespace, MqlMapConfiguration configuration, NodeEntry entry, Object target) throws MongoORMException {
      return parser(namespace, configuration, entry, target);
    }
  };
  
}
 public class QueryExecutor implements MqlExecutor<Map<String, Object>> {

  @Override
  public Map<String, Object> parser(String namespace, MqlMapConfiguration configuration, NodeEntry entry, Object target) throws MongoORMException {
    List<Entry> entrys = entry.getNodeMappings();
    TypeHandler<?> typeHandler = entry.getTypeHandler();
    String mappingId = entry.getMappingId();
    if (mappingId != null) {
      MappingConfig mapping = (MappingConfig) configuration.getMapping(namespace, mappingId);
      entrys = mapping.getNodes();
      typeHandler = mapping.getTypeHandler();
    }

    Map<String, Object> query = new LinkedHashMap<String, Object>();
    for (Entry ety : entrys) {
      StrategyContext context = new StrategyContext(ety, target, callback);
      context.setTypeHandler(typeHandler);
      
      new StrategyChain().doStrategy(namespace, configuration, context);
      
      Object value = context.getValue();
      if(!ObjectUtils.checkValueNull(value, ety)) {
        String column = ety.getColumn();
        String operate = ety.getOperate();
        
        if(operate == null) {
          query.put(column, value);
        } else {
          if(column == null) {
            query.put(operate, value);
          } else {
            Map<String, Object> qNode = new LinkedHashMap<String, Object>();
            qNode.put(operate, value); 
            query.put(column, qNode);
          }
        }
      }
    }
    return query;
  }

  CallBack<Map<String, Object>> callback = new CallBack<Map<String, Object>>() {
    @Override
    public Map<String, Object> callback(String namespace, MqlMapConfiguration configuration, NodeEntry entry, Object target) throws MongoORMException {
      return parser(namespace, configuration, entry, target);
    }
  };

}
 public class NodeletUtils {

  private NodeletUtils() {}
  
  public static Properties parseAttributes(Node node) {
    Properties attributes = new Properties();
    NamedNodeMap attributeNodes = node.getAttributes();
    for (int i = 0; i < attributeNodes.getLength(); i++) {
      Node attribute = attributeNodes.item(i);
      attributes.put(attribute.getNodeName(), attribute.getNodeValue());
    }
    return attributes;
  }
  
  public static List<Entry> getMappingEntry(MappingConfig mapping, MqlMapConfiguration configuration) {
    List<Entry> list = new ArrayList<Entry>();
    getEntrys(list, mapping, configuration);
    return list;
  }
  
  private static void getEntrys(List<Entry> list, MappingConfig mapping, MqlMapConfiguration configuration) {
    String extend = mapping.getExtend();
    if (extend != null) {
      getEntrys(list, (MappingConfig)configuration.getMapping(mapping.getNamespace(), mapping.getId()), configuration);
    }
    list.addAll(mapping.getNodes());
  }
}

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.yy.mongodb.constant.ORM;
import org.yy.mongodb.exception.StatementException;
import org.yy.mongodb.orm.builder.dynamic.Dynamic;
import org.yy.mongodb.orm.builder.dynamic.DynamicFactory;
import org.yy.mongodb.orm.engine.Config;
import org.yy.mongodb.orm.engine.entry.ColumnType;
import org.yy.mongodb.orm.engine.entry.Entry;
import org.yy.mongodb.orm.engine.entry.NodeEntry;
import org.yy.mongodb.orm.engine.entry.Operator;
import org.yy.mongodb.orm.engine.type.TypeHandlerFactory;
import org.yy.mongodb.orm.executor.MqlExecutor;
import org.yy.mongodb.orm.executor.parser.ActionExecutor;
import org.yy.mongodb.orm.executor.parser.FieldExecutor;
import org.yy.mongodb.orm.executor.parser.OrderExecutor;
import org.yy.mongodb.orm.executor.parser.QueryExecutor;
import org.yy.mongodb.util.NodeletUtils;

package org.yy.mongodb.orm.builder.statement;



/**
 * Base statement handler for convenience.
 * @author yy
 */
public abstract class BaseStatement implements StatementHandler {
  
  protected static MqlExecutor<?> queryExecutor = new QueryExecutor();
  protected static MqlExecutor<?> fieldExecutor = new FieldExecutor();
  protected static MqlExecutor<?> actionExecutor = new ActionExecutor();
  protected static MqlExecutor<?> orderExecutor = new OrderExecutor();
  

  protected List<Entry> getEntry(NodeList nodes, Class<?> clazz) {
