com.joyfulmongo.db.JFMongoCmdQuery.java Source code

Java tutorial

Introduction

Here is the source code for com.joyfulmongo.db.JFMongoCmdQuery.java

Source

/*
 * Copyright 2014 Weifeng Bao
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/
package com.joyfulmongo.db;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Logger;

import org.json.JSONArray;
import org.json.JSONObject;

import com.joyfulmongo.controller.JFCConstants;
import com.joyfulmongo.db.javadriver.JFDBObject;
import com.joyfulmongo.db.javadriver.JFDBQuery;

public class JFMongoCmdQuery extends JFMongoCmd {
    private static Logger LOGGER = Logger.getLogger(JFMongoCmdQuery.class.getName());

    public static Integer S_DEFAULT_SKIP = 0;
    public static Integer S_DEFAULT_LIMIT = 100;

    private JFDBQuery query;
    private String collectionName;
    private String[] includeFields;
    private String redirectClassname;

    private JFMongoCmdQuery(String colname, JFDBQuery dbquery, String redirectClassname) {
        this.collectionName = colname;
        this.query = dbquery;
        this.redirectClassname = redirectClassname;
    }

    @Override
    protected void beforeExecute() {
    }

    @Override
    protected JFMongoCmdResult execute() {
        List<JFMongoObject> parseObjs = find();
        JFMongoCmdResult result = new JFMongoCmdResult();
        result.put(JFCConstants.Props.results.toString(), parseObjs);
        if (this.redirectClassname != null) {
            result.put(JFCConstants.Props.classname.toString(), redirectClassname);
        }
        return result;
    }

    @Override
    protected JFMongoCmdResult afterExecute(JFMongoCmdResult executeResult) {
        return executeResult;
    }

    private void setIncludeFields(String... includeFields) {
        this.includeFields = includeFields;
    }

    public List<JFMongoObject> find() {
        List<JFDBObject> objs = query.find();

        Map<String, ContainerObjectRelation> relationKeyToClassnameMap = getRelationKeyToClassnameMap();

        List<JFMongoObject> results = new ArrayList<JFMongoObject>(objs.size());

        Map<String, LinkedHashMap<String, List<JFMongoObject>>> includeKeyToParentObjectMap = initPointerMap();
        Map<String, String> includeKeyToPointerColnameMap = new HashMap<String, String>(0);

        for (JFDBObject obj : objs) {
            JFMongoObject parseObj = new JFMongoObject(this.collectionName, obj);

            JSONObject json = parseObj.toJson();
            Iterator<String> relKeys = relationKeyToClassnameMap.keySet().iterator();
            while (relKeys.hasNext()) {
                String relKey = relKeys.next();
                if (!json.has(relKey)) {
                    ContainerObjectRelation rel = relationKeyToClassnameMap.get(relKey);
                    json.put(relKey, rel.toJson());
                }
            }

            results.add(parseObj);
            linkIncludeObjectIdToParentObject(parseObj, includeKeyToParentObjectMap, includeKeyToPointerColnameMap);
        }

        processIncludes(includeKeyToParentObjectMap, includeKeyToPointerColnameMap);

        return results;
    }

    private Map<String, ContainerObjectRelation> getRelationKeyToClassnameMap() {
        JFDBQuery.Builder distinctRelKeyQuery = new JFDBQuery.Builder(
                JFMongoRelationshipMetadata.S_METADATA_COLLNAME);
        JSONObject constraints = new JSONObject();
        constraints.put(JFMongoRelationshipMetadata.Props.relClassName.toString(), this.collectionName);
        distinctRelKeyQuery.constraints(constraints);

        JFDBQuery query = distinctRelKeyQuery.build();
        List<JFDBObject> objs = query.find();

        Map<String, ContainerObjectRelation> result = new HashMap<String, ContainerObjectRelation>(0);
        for (JFDBObject obj : objs) {
            JSONObject json = obj.toJson();
            String key = json.getString(JFMongoRelationshipMetadata.Props.relKey.toString());
            String pointerClassname = json.getString(JFMongoRelationshipMetadata.Props.pointerClassName.toString());
            ContainerObjectRelation rel = new ContainerObjectRelation(pointerClassname);
            result.put(key, rel);
        }

        return result;
    }

    private Map<String, LinkedHashMap<String, List<JFMongoObject>>> initPointerMap() {
        Map<String, LinkedHashMap<String, List<JFMongoObject>>> pointerMap = new HashMap<String, LinkedHashMap<String, List<JFMongoObject>>>();

        if (includeFields != null && includeFields.length > 0) {
            for (String includeKey : includeFields) {
                LinkedHashMap<String, List<JFMongoObject>> pointers = new LinkedHashMap<String, List<JFMongoObject>>(
                        0);
                pointerMap.put(includeKey, pointers);
            }
        }

        return pointerMap;
    }

    private void linkIncludeObjectIdToParentObject(JFMongoObject parentObject,
            Map<String, LinkedHashMap<String, List<JFMongoObject>>> pointerMap,
            Map<String, String> includeKeyToPointerColnameMap) {
        for (String includeKey : includeFields) {
            if (includeKey.length() > 0) {
                ContainerObjectPointer[] pointers = parentObject.getPointer(includeKey);
                for (ContainerObjectPointer pointer : pointers) {
                    String pointerObjectId = pointer.getObjectId();
                    LinkedHashMap<String, List<JFMongoObject>> pointerObjectIdToParentObjectMap = pointerMap
                            .get(includeKey);
                    List<JFMongoObject> parentObjects = pointerObjectIdToParentObjectMap.get(pointerObjectId);
                    if (parentObjects == null) {
                        parentObjects = new ArrayList<JFMongoObject>(1);
                        pointerObjectIdToParentObjectMap.put(pointerObjectId, parentObjects);
                    }
                    parentObjects.add(parentObject);

                    includeKeyToPointerColnameMap.put(includeKey, pointer.getClassName());
                }
            }
        }
    }

    private void processIncludes(Map<String, LinkedHashMap<String, List<JFMongoObject>>> includeKeyToPointerListMap,
            Map<String, String> includeKeyToPointerColnameMap) {
        for (String includeKey : includeFields) {
            String pointerColName = includeKeyToPointerColnameMap.get(includeKey);
            if (pointerColName != null) {
                LinkedHashMap<String, List<JFMongoObject>> pointerObjectIdToParentObjectsMap = includeKeyToPointerListMap
                        .get(includeKey);
                Set<String> referreeObjIds = pointerObjectIdToParentObjectsMap.keySet();

                JFMongoCmdQuery.Builder queryBuilder = new JFMongoCmdQuery.Builder(pointerColName);
                queryBuilder.whereContainedIn(Constants.Props.objectId.toString(), referreeObjIds);
                List<JFMongoObject> refereeObjects = queryBuilder.build().find();

                for (JFMongoObject refereeObj : refereeObjects) {
                    String refereeObjId = refereeObj.getObjectId();
                    List<JFMongoObject> parentObjs = pointerObjectIdToParentObjectsMap.get(refereeObjId);
                    for (JFMongoObject parentObj : parentObjs) {
                        ContainerObjectPointer[] pointers = parentObj.getPointer(includeKey);
                        for (ContainerObjectPointer pointer : pointers) {
                            pointer.replaceObject(refereeObj);
                        }
                    }
                }
            }
        }
    }

    public static class Builder {
        private String colname;
        private JFDBQuery.Builder dbQueryBuilder;
        private JSONObject constraints;
        private List<String> includes;
        private List<String> projections;
        private List<String> projectionsExclude;
        private List<String> sorts;
        private int limit;
        private int skip;
        private String redirectClassNameForKey;
        private String redirectClassName;

        public Builder(String colname) {
            if (colname == null || colname.length() == 0) {
                throw new IllegalArgumentException("Collection name can not be null or zero length");
            }

            dbQueryBuilder = new JFDBQuery.Builder(colname);

            this.colname = colname;
            this.constraints = new JSONObject();
            this.projections = new ArrayList<String>(0);
            this.projectionsExclude = new ArrayList<String>(0);
            this.sorts = new ArrayList<String>(0);
            this.includes = new ArrayList<String>(0);
            this.limit = S_DEFAULT_LIMIT;
            this.skip = S_DEFAULT_SKIP;
            this.redirectClassNameForKey = null;
            this.redirectClassName = null;
        }

        public void collection(String colname) {
            this.dbQueryBuilder.collection(colname);
            this.colname = colname;
        }

        public String getCollection() {
            return this.colname;
        }

        public Builder projection(String... fields) {
            for (String field : fields) {
                projections.add(field);
            }
            return this;
        }

        String[] getProjections() {
            String[] results = new String[projections.size()];
            results = projections.toArray(results);
            return results;
        }

        public Builder projectionExclude(String... fields) {
            for (String field : fields) {
                projectionsExclude.add(field);
            }
            return this;
        }

        String[] getProjectionsExclude() {
            String[] results = new String[projectionsExclude.size()];
            results = projectionsExclude.toArray(results);
            return results;
        }

        public Builder include(String... fields) {
            for (String field : fields) {
                includes.add(field);
            }
            return this;
        }

        String[] getIncludes() {
            String[] results = new String[includes.size()];
            results = includes.toArray(results);
            return results;
        }

        public Builder limit(int limit) {
            this.limit = limit;
            return this;
        }

        int getLimit() {
            return this.limit;
        }

        public Builder skip(int skip) {
            this.skip = skip;
            return this;
        }

        int getSkip() {
            return this.skip;
        }

        public Builder redirectClassNameForKey(String redirectClassNameForKey) {
            if (redirectClassNameForKey != null && redirectClassNameForKey.length() != 0) {
                this.redirectClassNameForKey = redirectClassNameForKey;
            }
            return this;
        }

        public Builder sort(String sorts) {
            StringTokenizer st = new StringTokenizer(sorts, ",");
            while (st.hasMoreTokens()) {
                this.sorts.add(st.nextToken());
            }
            return this;
        }

        String getSort() {
            String result = "";
            if (sorts.size() > 0) {
                result = sorts.get(0);
            }

            for (int i = 1; i < sorts.size(); i++) {
                result += "," + sorts.get(i);
            }
            return result;
        }

        public Builder constraints(JSONObject constraints) {
            this.constraints = constraints;
            return this;
        }

        public Builder whereEquals(String key, String value) {
            this.constraints.put(key, value);
            return this;
        }

        public void whereContainedIn(String key, Collection<String> objIds) {
            JSONArray array = new JSONArray();
            for (String objId : objIds) {
                array.put(objId);
            }
            JSONObject inCondition = new JSONObject();
            inCondition.put("$in", array);
            constraints.put(key, inCondition);
        }

        JSONObject getConstraints() {
            return this.constraints;
        }

        public JFMongoCmdQuery build() {
            Builder theBuilder = this;
            if (QueryConditionFilterRelation.isRelationQuery(constraints)) {
                QueryConditionFilterRelation relationCondition = new QueryConditionFilterRelation(this);
                List<String> objIds = relationCondition.getRelationObjectIds();
                whereContainedIn(Constants.Props.objectId.toString(), objIds);
                QueryConditionFilterRelation.adjustConstraints(constraints);

                if (redirectClassNameForKey != null) {
                    this.redirectClassName = relationCondition.getRedirectClassNameForKey(redirectClassNameForKey);
                    if (this.redirectClassName != null) {
                        collection(this.redirectClassName);
                    }
                }
            }

            JSONObject effectiveConstraints = theBuilder.getConstraints();

            convertConstraints(null, effectiveConstraints);

            QueryConditionFilterGeoQuery.adjustConstraints(effectiveConstraints);
            dbQueryBuilder.constraints(effectiveConstraints);
            dbQueryBuilder.projection(theBuilder.getProjections());
            dbQueryBuilder.projectionExclude(theBuilder.getProjectionsExclude());
            dbQueryBuilder.limit(theBuilder.getLimit());
            dbQueryBuilder.skip(theBuilder.getSkip());
            dbQueryBuilder.sort(theBuilder.getSort());

            JFDBQuery dbquery = dbQueryBuilder.build();
            JFMongoCmdQuery query = new JFMongoCmdQuery(colname, dbquery, redirectClassName);
            query.setIncludeFields(theBuilder.getIncludes());
            return query;
        }

        private void convertConstraints(String jsonkey, JSONObject json) {
            Iterator<String> keys = json.keys();
            while (keys.hasNext()) {
                String key = keys.next();

                Object childObj = json.get(key);
                if (childObj instanceof JSONObject) {
                    ContainerObject cobj = ContainerObjectFactory.getChildObject(key, childObj);
                    if (cobj != null) {
                        if (cobj instanceof ContainerObjectDefault) {
                            JSONObject childJson = json.getJSONObject(key);
                            convertConstraints(key, childJson);
                        } else {
                            cobj.onQuery(key, json);
                        }
                    } else {
                        convertConstraints(key, (JSONObject) childObj);
                    }
                }
            }
        }
    }
}