com.bugull.mongo.BuguUpdater.java Source code

Java tutorial

Introduction

Here is the source code for com.bugull.mongo.BuguUpdater.java

Source

/*
 * Copyright (c) www.bugull.com
 * 
 * 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.bugull.mongo;

import com.bugull.mongo.cache.FieldsCache;
import com.bugull.mongo.lucene.backend.EntityChangedListener;
import com.bugull.mongo.lucene.backend.IndexChecker;
import com.bugull.mongo.utils.IdUtil;
import com.bugull.mongo.utils.MapperUtil;
import com.bugull.mongo.utils.Operator;
import com.bugull.mongo.utils.ReferenceUtil;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.WriteConcern;
import com.mongodb.WriteResult;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * There are so many update operation, so put it together here.
 * 
 * @author Frank Wen(xbwen@hotmail.com)
 */
@SuppressWarnings("unchecked")
public class BuguUpdater<T> {

    private DBCollection coll;
    private Class<T> clazz;
    private WriteConcern concern;
    private EntityChangedListener luceneListener;

    public BuguUpdater(DBCollection coll, Class<T> clazz, WriteConcern concern,
            EntityChangedListener luceneListener) {
        this.coll = coll;
        this.clazz = clazz;
        this.concern = concern;
        this.luceneListener = luceneListener;
    }

    private T findOne(String id) {
        DBObject dbo = new BasicDBObject();
        dbo.put(Operator.ID, IdUtil.toDbId(clazz, id));
        DBObject result = coll.findOne(dbo);
        return MapperUtil.fromDBObject(clazz, result);
    }

    private WriteResult updateOne(String id, DBObject dbo, String... keys) {
        DBObject condition = new BasicDBObject(Operator.ID, IdUtil.toDbId(clazz, id));
        WriteResult wr = coll.update(condition, dbo, false, false, concern); //update one
        if (luceneListener != null && IndexChecker.hasIndexAnnotation(clazz, keys)) {
            BuguEntity entity = (BuguEntity) findOne(id);
            luceneListener.entityUpdate(entity);
        }
        return wr;
    }

    private WriteResult updateMulti(DBObject condition, DBObject dbo, String... keys) {
        WriteResult wr = coll.update(condition, dbo, false, true, concern); //update multi
        if (luceneListener != null && IndexChecker.hasIndexAnnotation(clazz, keys)) {
            List ids = coll.distinct(Operator.ID, condition);
            for (Object id : ids) {
                BuguEntity entity = (BuguEntity) findOne(id.toString());
                luceneListener.entityUpdate(entity);
            }
        }
        return wr;
    }

    private Object checkSingleValue(String key, Object value) {
        Object result = value;
        if (value instanceof BuguEntity) {
            BuguEntity be = (BuguEntity) value;
            result = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId());
        } else if (!(value instanceof DBObject) && FieldsCache.getInstance().isEmbedField(clazz, key)) {
            result = MapperUtil.toDBObject(value);
        }
        return result;
    }

    private Object checkArrayValue(String key, Object value) {
        Object result = value;
        if (value instanceof BuguEntity) {
            BuguEntity be = (BuguEntity) value;
            result = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId());
        } else if (!(value instanceof DBObject) && FieldsCache.getInstance().isEmbedListField(clazz, key)) {
            result = MapperUtil.toDBObject(value);
        }
        return result;
    }

    /**
     * Update some entities, with new key/value pairs.
     * Notice: EmbedList and RefList fields is not supported yet.
     * @param query the query condition
     * @param key the field's name
     * @param value the field's new value
     * @return 
     */
    public WriteResult set(BuguQuery query, String key, Object value) {
        value = checkSingleValue(key, value);
        DBObject dbo = new BasicDBObject(key, value);
        DBObject set = new BasicDBObject(Operator.SET, dbo);
        return updateMulti(query.getCondition(), set, key);
    }

    /**
     * Update some entities, with new key/value pairs.
     * Notice: the Map values must can be converted to DBObject.
     * @param query the query condition
     * @param values
     * @return the new key/value pairs
     */
    public WriteResult set(BuguQuery query, Map values) {
        DBObject dbo = new BasicDBObject(values);
        DBObject set = new BasicDBObject(Operator.SET, dbo);
        Set<String> keys = (Set<String>) values.keySet();
        return updateMulti(query.getCondition(), set, keys.toArray(new String[0]));
    }

    /**
     * Update a field's value of an entity.
     * Notice: EmbedList and RefList fields is not supported yet.
     * @param t the entity needs to update
     * @param key the field's name
     * @param value the field's new value
     * @return 
     */
    public WriteResult set(T t, String key, Object value) {
        BuguEntity ent = (BuguEntity) t;
        return set(ent.getId(), key, value);
    }

    /**
     * Update a field's value of an entity.
     * Notice: EmbedList and RefList fields is not supported yet.
     * @param id the entity's id
     * @param key the field's name
     * @param value the field's new value
     * @return 
     */
    public WriteResult set(String id, String key, Object value) {
        value = checkSingleValue(key, value);
        DBObject query = new BasicDBObject(key, value);
        DBObject set = new BasicDBObject(Operator.SET, query);
        return updateOne(id, set, key);
    }

    /**
     * Update an entity, with new key/value pairs.
     * Notice: the Map values must can be converted to DBObject.
     * @param t the entity needs to be updated
     * @param values the new key/value pairs
     * @return 
     */
    public WriteResult set(T t, Map values) {
        BuguEntity ent = (BuguEntity) t;
        return set(ent.getId(), values);
    }

    /**
     * Update an entity, with new key/value pairs.
     * Notice: the Map values must can be converted to DBObject.
     * @param id the entity's id
     * @param values the new key/value pairs
     * @return 
     */
    public WriteResult set(String id, Map values) {
        DBObject set = new BasicDBObject(Operator.SET, new BasicDBObject(values));
        Set<String> keys = (Set<String>) values.keySet();
        return updateOne(id, set, keys.toArray(new String[0]));
    }

    /**
     * Remove one or more filed(column) of an entity.
     * @param t the entity to operate
     * @param keys the field's name
     * @return 
     */
    public WriteResult unset(T t, String... keys) {
        BuguEntity ent = (BuguEntity) t;
        return unset(ent.getId(), keys);
    }

    /**
     * Remove one or more filed(column) of an entity
     * @param id the entity's id
     * @param keys the field's name
     * @return 
     */
    public WriteResult unset(String id, String... keys) {
        DBObject query = new BasicDBObject();
        for (String key : keys) {
            query.put(key, 1);
        }
        DBObject unset = new BasicDBObject(Operator.UNSET, query);
        return updateOne(id, unset, keys);
    }

    /**
     * Remove one or more filed(column).
     * @param query mathcing conditon
     * @param keys the field's name
     * @return 
     */
    public WriteResult unset(BuguQuery query, String... keys) {
        DBObject dbo = new BasicDBObject();
        for (String key : keys) {
            dbo.put(key, 1);
        }
        DBObject unset = new BasicDBObject(Operator.UNSET, dbo);
        return updateMulti(query.getCondition(), unset, keys);
    }

    /**
     * Increase a numeric field of an entity.
     * @param t the entity needs to update
     * @param key the field's name
     * @param value the numeric value to be added. It can be positive or negative integer, long, float, double.
     * @return 
     */
    public WriteResult inc(T t, String key, Object value) {
        BuguEntity ent = (BuguEntity) t;
        return inc(ent.getId(), key, value);
    }

    /**
     * Increase a numeric field of an entity.
     * @param id the entity's id
     * @param key the field's name
     * @param value the numeric value to be added. It can be positive or negative integer, long, float, double.
     * @return 
     */
    public WriteResult inc(String id, String key, Object value) {
        DBObject dbo = new BasicDBObject(key, value);
        DBObject inc = new BasicDBObject(Operator.INC, dbo);
        return updateOne(id, inc, key);
    }

    /**
     * Increase a numberic field of some entities.
     * @param query the query condition
     * @param key the field's name
     * @param value the numeric value to be added. It can be positive or negative integer, long, float, double.
     * @return 
     */
    public WriteResult inc(BuguQuery query, String key, Object value) {
        DBObject dbo = new BasicDBObject(key, value);
        DBObject inc = new BasicDBObject(Operator.INC, dbo);
        return updateMulti(query.getCondition(), inc, key);
    }

    /**
     * Multiply the value of a field by a number. 
     * @param t the entity to update
     * @param key the field's name
     * @param value the numeric value to multiply
     * @return 
     */
    public WriteResult mul(T t, String key, Object value) {
        BuguEntity ent = (BuguEntity) t;
        return mul(ent.getId(), key, value);
    }

    /**
     * Multiply the value of a field by a number. 
     * @param id the entity's id
     * @param key the field's name
     * @param value the numeric value to multiply
     * @return 
     */
    public WriteResult mul(String id, String key, Object value) {
        DBObject dbo = new BasicDBObject(key, value);
        DBObject mul = new BasicDBObject(Operator.MUL, dbo);
        return updateOne(id, mul, key);
    }

    /**
     * Multiply the value of a field by a number. 
     * @param query the query condition
     * @param key the field's name
     * @param value the numeric value to multiply
     * @return 
     */
    public WriteResult mul(BuguQuery query, String key, Object value) {
        DBObject dbo = new BasicDBObject(key, value);
        DBObject mul = new BasicDBObject(Operator.MUL, dbo);
        return updateMulti(query.getCondition(), mul, key);
    }

    /**
     * Add an element to an entity's array/list/set field.
     * @param t the entity needs to update
     * @param key the field's name
     * @param value the element to add
     * @return 
     */
    public WriteResult push(T t, String key, Object value) {
        BuguEntity ent = (BuguEntity) t;
        return push(ent.getId(), key, value);
    }

    /**
     * Add an element to an entity's array/list/set field.
     * @param id the entity's id
     * @param key the field's name
     * @param value the element to add
     * @return 
     */
    public WriteResult push(String id, String key, Object value) {
        value = checkArrayValue(key, value);
        DBObject dbo = new BasicDBObject(key, value);
        DBObject push = new BasicDBObject(Operator.PUSH, dbo);
        return updateOne(id, push, key);
    }

    /**
     * Add an element to array/list/set field.
     * @param query the query condition
     * @param key the field's name
     * @param value the element to add
     * @return 
     */
    public WriteResult push(BuguQuery query, String key, Object value) {
        value = checkArrayValue(key, value);
        DBObject dbo = new BasicDBObject(key, value);
        DBObject push = new BasicDBObject(Operator.PUSH, dbo);
        return updateMulti(query.getCondition(), push, key);
    }

    /**
     * Add each element in a list to the specified field.
     * @param t the entity to update
     * @param key the field's name
     * @param valueList the list contains each element
     * @return 
     */
    public WriteResult pushEach(T t, String key, List valueList) {
        BuguEntity ent = (BuguEntity) t;
        return pushEach(ent.getId(), key, valueList);
    }

    /**
     * Add each element in a list to the specified field.
     * @param id the entity's id
     * @param key the field's name
     * @param valueList the list contains each element
     * @return 
     */
    public WriteResult pushEach(String id, String key, List valueList) {
        int len = valueList.size();
        Object[] values = new Object[len];
        for (int i = 0; i < len; i++) {
            values[i] = checkArrayValue(key, valueList.get(i));
        }
        DBObject each = new BasicDBObject(Operator.EACH, values);
        DBObject dbo = new BasicDBObject(key, each);
        DBObject push = new BasicDBObject(Operator.PUSH, dbo);
        return updateOne(id, push, key);
    }

    /**
     * Add each element in a list to the specified field.
     * @param query the query condition
     * @param key the field's name
     * @param valueList the list contains each element
     * @return 
     */
    public WriteResult pushEach(BuguQuery query, String key, List valueList) {
        int len = valueList.size();
        Object[] values = new Object[len];
        for (int i = 0; i < len; i++) {
            values[i] = checkArrayValue(key, valueList.get(i));
        }
        DBObject each = new BasicDBObject(Operator.EACH, values);
        DBObject dbo = new BasicDBObject(key, each);
        DBObject push = new BasicDBObject(Operator.PUSH, dbo);
        return updateMulti(query.getCondition(), push, key);
    }

    /**
     * Remove an element of an entity's array/list/set field.
     * @param t the entity needs to update
     * @param key the field's name
     * @param value the element to remove
     * @return 
     */
    public WriteResult pull(T t, String key, Object value) {
        BuguEntity ent = (BuguEntity) t;
        return pull(ent.getId(), key, value);
    }

    /**
     * Remove an element of an entity's array/list/set field.
     * @param id the entity's id
     * @param key the field's name
     * @param value the element to remove
     * @return 
     */
    public WriteResult pull(String id, String key, Object value) {
        value = checkArrayValue(key, value);
        DBObject dbo = new BasicDBObject(key, value);
        DBObject pull = new BasicDBObject(Operator.PULL, dbo);
        return updateOne(id, pull, key);
    }

    /**
     * Remove an element from array/list/set field.
     * @param query the query condition
     * @param key the field's name
     * @param value the element to remove
     * @return 
     */
    public WriteResult pull(BuguQuery query, String key, Object value) {
        value = checkArrayValue(key, value);
        DBObject dbo = new BasicDBObject(key, value);
        DBObject pull = new BasicDBObject(Operator.PULL, dbo);
        return updateMulti(query.getCondition(), pull, key);
    }

    /**
     * Remove the first element from the array/list/set field
     * @param t the entity to update
     * @param key the field's name
     * @return 
     */
    public WriteResult popFirst(T t, String key) {
        BuguEntity ent = (BuguEntity) t;
        return popFirst(ent.getId(), key);
    }

    /**
     * Remove the first element from the array/list/set field
     * @param id the entity's id
     * @param key the field's name
     * @return 
     */
    public WriteResult popFirst(String id, String key) {
        DBObject dbo = new BasicDBObject(key, -1);
        DBObject pop = new BasicDBObject(Operator.POP, dbo);
        return updateOne(id, pop, key);
    }

    /**
     * Remove the first element from the array/list/set field
     * @param query the query condition
     * @param key the field's name
     * @return 
     */
    public WriteResult popFirst(BuguQuery query, String key) {
        DBObject dbo = new BasicDBObject(key, -1);
        DBObject pop = new BasicDBObject(Operator.POP, dbo);
        return updateMulti(query.getCondition(), pop, key);
    }

    /**
     * Remove the last element from the array/list/set field
     * @param t the entity to update
     * @param key the field's name
     * @return 
     */
    public WriteResult popLast(T t, String key) {
        BuguEntity ent = (BuguEntity) t;
        return popLast(ent.getId(), key);
    }

    /**
     * Remove the last element from the array/list/set field
     * @param id the entity's id
     * @param key the field's name
     * @return 
     */
    public WriteResult popLast(String id, String key) {
        DBObject dbo = new BasicDBObject(key, 1);
        DBObject pop = new BasicDBObject(Operator.POP, dbo);
        return updateOne(id, pop, key);
    }

    /**
     * Remove the last element from the array/list/set field
     * @param query the query condition
     * @param key the field's name
     * @return 
     */
    public WriteResult popLast(BuguQuery query, String key) {
        DBObject dbo = new BasicDBObject(key, 1);
        DBObject pop = new BasicDBObject(Operator.POP, dbo);
        return updateMulti(query.getCondition(), pop, key);
    }

    /**
     * Update the value of the field to a specified value if the specified value is less than the current value of the field.
     * If the field does not exists, this operation sets the field to the specified value. 
     * @param t the entity needs to update
     * @param key the field's name
     * @param value the specified value
     * @return 
     */
    public WriteResult min(T t, String key, Object value) {
        BuguEntity ent = (BuguEntity) t;
        return min(ent.getId(), key, value);
    }

    /**
     * Update the value of the field to a specified value if the specified value is less than the current value of the field.
     * If the field does not exists, this operation sets the field to the specified value. 
     * @param id the entity's id
     * @param key the field's name
     * @param value the specified value
     * @return 
     */
    public WriteResult min(String id, String key, Object value) {
        DBObject dbo = new BasicDBObject(key, value);
        DBObject min = new BasicDBObject(Operator.MIN, dbo);
        return updateOne(id, min, key);
    }

    /**
     * Update the value of the field to a specified value if the specified value is less than the current value of the field.
     * If the field does not exists, this operation sets the field to the specified value. 
     * @param query the query conditon
     * @param key the field's name
     * @param value the specified value
     * @return 
     */
    public WriteResult min(BuguQuery query, String key, Object value) {
        DBObject dbo = new BasicDBObject(key, value);
        DBObject min = new BasicDBObject(Operator.MIN, dbo);
        return updateMulti(query.getCondition(), min, key);
    }

    /**
     * updates the value of the field to a specified value if the specified value is greater than the current value of the field.
     * If the field does not exists, this operation sets the field to the specified value. 
     * @param t the entity needs to update
     * @param key the field's name
     * @param value the specified value
     * @return 
     */
    public WriteResult max(T t, String key, Object value) {
        BuguEntity ent = (BuguEntity) t;
        return max(ent.getId(), key, value);
    }

    /**
     * updates the value of the field to a specified value if the specified value is greater than the current value of the field.
     * If the field does not exists, this operation sets the field to the specified value. 
     * @param id the entity's id
     * @param key the field's name
     * @param value the specified value
     * @return 
     */
    public WriteResult max(String id, String key, Object value) {
        DBObject dbo = new BasicDBObject(key, value);
        DBObject max = new BasicDBObject(Operator.MAX, dbo);
        return updateOne(id, max, key);
    }

    /**
     * updates the value of the field to a specified value if the specified value is greater than the current value of the field.
     * If the field does not exists, this operation sets the field to the specified value. 
     * @param query the query condition
     * @param key the field's name
     * @param value the specified value
     * @return 
     */
    public WriteResult max(BuguQuery query, String key, Object value) {
        DBObject dbo = new BasicDBObject(key, value);
        DBObject max = new BasicDBObject(Operator.MAX, dbo);
        return updateMulti(query.getCondition(), max, key);
    }

    /**
     * Performs a bitwise update of a field
     * @param t the entity to update
     * @param key the field's name
     * @param value the bitwise value
     * @param bitwise the enum type of bitwise operation: AND,OR,XOR
     * @return 
     */
    public WriteResult bitwise(T t, String key, int value, Bitwise bitwise) {
        BuguEntity ent = (BuguEntity) t;
        return bitwise(ent.getId(), key, value, bitwise);
    }

    /**
     * Performs a bitwise update of a field
     * @param id the entity's id
     * @param key the field's name
     * @param value the bitwise value
     * @param bitwise the enum type of bitwise operation: AND,OR,XOR
     * @return 
     */
    public WriteResult bitwise(String id, String key, int value, Bitwise bitwise) {
        DBObject logic = new BasicDBObject(checkBitwise(bitwise), value);
        DBObject dbo = new BasicDBObject(key, logic);
        DBObject bit = new BasicDBObject(Operator.BIT, dbo);
        return updateOne(id, bit, key);
    }

    /**
     * Performs a bitwise update of a field
     * @param query the query condition
     * @param key the field's name
     * @param value the bitwise value
     * @param bitwise the enum type of bitwise operation: AND,OR,XOR
     * @return 
     */
    public WriteResult bitwise(BuguQuery query, String key, int value, Bitwise bitwise) {
        DBObject logic = new BasicDBObject(checkBitwise(bitwise), value);
        DBObject dbo = new BasicDBObject(key, logic);
        DBObject bit = new BasicDBObject(Operator.BIT, dbo);
        return updateMulti(query.getCondition(), bit, key);
    }

    private String checkBitwise(Bitwise bitwise) {
        String result = null;
        switch (bitwise) {
        case AND:
            result = "and";
            break;
        case OR:
            result = "or";
            break;
        case XOR:
            result = "xor";
            break;
        default:
            break;
        }
        return result;
    }

    public enum Bitwise {
        AND, OR, XOR
    }

}