/* * 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 net.tooan.ynpay.third.mongodb; import com.mongodb.*; import net.tooan.ynpay.third.jfinal.log.Logger; import net.tooan.ynpay.third.mongodb.annotations.*; import net.tooan.ynpay.third.mongodb.cache.FieldsCache; import net.tooan.ynpay.third.mongodb.exception.DBConnectionException; import net.tooan.ynpay.third.mongodb.exception.IdException; import net.tooan.ynpay.third.mongodb.lucene.backend.EntityChangedListener; import net.tooan.ynpay.third.mongodb.lucene.backend.IndexChecker; import net.tooan.ynpay.third.mongodb.mapper.*; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; /** * The basic Dao class. * * @author Frank Wen(xbwen@hotmail.com) */ public class BuguDao<T> { private final static Logger logger = Logger.getLogger(BuguDao.class); protected DBCollection coll; protected Class<T> clazz; protected DBObject keys; //non-lazy fields protected EntityChangedListener luceneListener; protected EntityRemovedListener cascadeListener; public BuguDao(Class<T> clazz) { this.clazz = clazz; DB db = null; Entity entity = clazz.getAnnotation(Entity.class); String[] name = MapperUtil.getEntityName(clazz); try { db = BuguConnection.getInstance().getDB(name[0]); } catch (DBConnectionException ex) { logger.error(ex.getMessage(), ex); } //if capped if (entity.capped() && !db.collectionExists(name[1])) { DBObject options = new BasicDBObject("capped", true); long capSize = entity.capSize(); if (capSize != Default.CAP_SIZE) { options.put("size", capSize); } long capMax = entity.capMax(); if (capMax != Default.CAP_MAX) { options.put("max", capMax); } coll = db.createCollection(name[1], options); } else { coll = db.getCollection(name[1]); } //for keys keys = MapperUtil.getKeyFields(clazz); //for @EnsureIndex EnsureIndex ei = clazz.getAnnotation(EnsureIndex.class); if (ei != null) { List<DBIndex> list = MapperUtil.getDBIndex(ei.value()); for (DBIndex dbi : list) { coll.ensureIndex(dbi.getKeys(), dbi.getOptions()); } } //for lucene if (IndexChecker.needListener(clazz)) { luceneListener = new EntityChangedListener(clazz); } //for cascade delete cascadeListener = new EntityRemovedListener(clazz); } /** * Insert an entity to mongoDB. * * @param t * @return */ public WriteResult insert(T t) { DBObject dbo = MapperUtil.toDBObject(t); WriteResult wr = coll.insert(dbo); String id = dbo.get(Operator.ID).toString(); BuguEntity ent = (BuguEntity) t; ent.setId(id); if (luceneListener != null) { luceneListener.entityInsert(ent); } return wr; } /** * Insert a list of entity to mongoDB. * * @param list * @return */ public WriteResult insert(List<T> list) { List<DBObject> dboList = new ArrayList<DBObject>(); for (T t : list) { dboList.add(MapperUtil.toDBObject(t)); } WriteResult wr = coll.insert(dboList); int len = dboList.size(); for (int i = 0; i < len; i++) { String id = dboList.get(i).get(Operator.ID).toString(); BuguEntity ent = (BuguEntity) (list.get(i)); ent.setId(id); } if (luceneListener != null) { for (T t : list) { luceneListener.entityInsert((BuguEntity) t); } } return wr; } /** * Save an entity to mongoDB. * If no id in it, then insert the entity. * Else, check the id type, to confirm do save or insert. * * @param t * @return */ public WriteResult save(T t) { WriteResult wr = null; BuguEntity ent = (BuguEntity) t; if (StringUtil.isEmpty(ent.getId())) { wr = insert(t); } else { Field idField = null; try { idField = FieldsCache.getInstance().getIdField(clazz); } catch (IdException ex) { logger.error(ex.getMessage(), ex); } Id idAnnotation = idField.getAnnotation(Id.class); if (idAnnotation.type() == IdType.USER_DEFINE) { if (this.exists(Operator.ID, ent.getId())) { wr = doSave(ent); } else { wr = insert(t); } } else { wr = doSave(ent); } } return wr; } private WriteResult doSave(BuguEntity ent) { WriteResult wr = coll.save(MapperUtil.toDBObject(ent)); if (luceneListener != null) { luceneListener.entityUpdate(ent); } return wr; } /** * Drop the collection. * It will automatically drop all indexes from this collection. */ public void drop() { if (luceneListener != null || cascadeListener.hasCascade()) { List<T> list = findAll(); for (T t : list) { remove(t); } } coll.drop(); coll.dropIndexes(); } /** * Remove an entity has id value in it. * * @param t * @return */ public WriteResult remove(T t) { BuguEntity ent = (BuguEntity) t; return remove(ent.getId()); } /** * Remove an entity by id. * * @param id * @return */ public WriteResult remove(String id) { if (cascadeListener.hasCascade()) { BuguEntity entity = (BuguEntity) findOne(id); cascadeListener.entityRemove(entity); } if (luceneListener != null) { luceneListener.entityRemove(id); } DBObject query = new BasicDBObject(); query.put(Operator.ID, IdUtil.toDbId(clazz, id)); return coll.remove(query); } /** * Remove by array of id. * * @param ids * @return */ public WriteResult remove(String... ids) { int len = ids.length; if (cascadeListener.hasCascade()) { for (int i = 0; i < len; i++) { BuguEntity entity = (BuguEntity) findOne(ids[i]); cascadeListener.entityRemove(entity); } } if (luceneListener != null) { for (int i = 0; i < len; i++) { luceneListener.entityRemove(ids[i]); } } Object[] arr = new Object[len]; for (int i = 0; i < len; i++) { arr[i] = IdUtil.toDbId(clazz, ids[i]); } DBObject in = new BasicDBObject(Operator.IN, arr); DBObject query = new BasicDBObject(Operator.ID, in); return coll.remove(query); } /** * Remove entity by condition. * * @param key the condition field * @param value the condition value * @return */ public WriteResult remove(String key, Object value) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } return remove(new BasicDBObject(key, value)); } /** * Remove by condition. * * @param query * @return */ public WriteResult remove(BuguQuery query) { return remove(query.getCondition()); } private WriteResult remove(DBObject query) { List<T> list = this.find(query); if (cascadeListener.hasCascade()) { for (T t : list) { cascadeListener.entityRemove((BuguEntity) t); } } if (luceneListener != null) { for (T t : list) { BuguEntity ent = (BuguEntity) t; luceneListener.entityRemove(ent.getId()); } } return coll.remove(query); } private WriteResult update(String id, DBObject dbo) { WriteResult wr = updateWithOutIndex(id, dbo); if (luceneListener != null) { BuguEntity entity = (BuguEntity) findOne(id); luceneListener.entityUpdate(entity); } return wr; } private WriteResult updateWithOutIndex(String id, DBObject dbo) { DBObject query = new BasicDBObject(Operator.ID, IdUtil.toDbId(clazz, id)); return coll.update(query, dbo); } public WriteResult set(BuguQuery query, String key, Object value) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } DBObject dbo = new BasicDBObject(key, value); return set(query.getCondition(), dbo); } /** * Update some entities, with new key/value pairs. * * @param query the query condition * @param dbo the new key/value pairs * @return */ public WriteResult set(DBObject query, DBObject dbo) { List ids = null; if (luceneListener != null) { ids = coll.distinct(Operator.ID, query); } WriteResult wr = coll.updateMulti(query, new BasicDBObject(Operator.SET, dbo)); if (luceneListener != null) { for (Object id : ids) { BuguEntity entity = (BuguEntity) findOne(id.toString()); luceneListener.entityUpdate(entity); } } return wr; } /** * Update a field's value of an entity. * * @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. * * @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) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } DBObject query = new BasicDBObject(key, value); DBObject set = new BasicDBObject(Operator.SET, query); if (luceneListener != null && IndexChecker.hasIndexAnnotation(clazz, key)) { return update(id, set); } else { return updateWithOutIndex(id, set); } } /** * Remove a filed(column) of an entity. * * @param t the entity to operate * @param key the field's name * @return */ public WriteResult unset(T t, String key) { BuguEntity ent = (BuguEntity) t; return unset(ent.getId(), key); } /** * Remove a filed(column) of an entity * * @param id the entity's id * @param key the field's name * @return */ public WriteResult unset(String id, String key) { DBObject query = new BasicDBObject(key, 1); DBObject unset = new BasicDBObject(Operator.UNSET, query); if (luceneListener != null && IndexChecker.hasIndexAnnotation(clazz, key)) { return update(id, unset); } else { return updateWithOutIndex(id, unset); } } /** * Remove a filed(column). * * @param query mathcing conditon * @param key the field's name * @return */ public WriteResult unset(BuguQuery query, String key) { return unset(query.getCondition(), key); } private WriteResult unset(DBObject query, String key) { boolean indexField = (luceneListener != null) && IndexChecker.hasIndexAnnotation(clazz, key); List ids = null; if (indexField) { ids = coll.distinct(Operator.ID, query); } DBObject dbo = new BasicDBObject(key, 1); WriteResult wr = coll.updateMulti(query, new BasicDBObject(Operator.UNSET, dbo)); if (indexField) { for (Object id : ids) { BuguEntity entity = (BuguEntity) findOne(id.toString()); luceneListener.entityUpdate(entity); } } return wr; } /** * 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 query = new BasicDBObject(key, value); DBObject inc = new BasicDBObject(Operator.INC, query); if (luceneListener != null && IndexChecker.hasIndexAnnotation(clazz, key)) { return update(id, inc); } else { return updateWithOutIndex(id, inc); } } /** * 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) { return inc(query.getCondition(), key, value); } /** * 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(DBObject query, String key, Object value) { List ids = null; if (luceneListener != null) { ids = coll.distinct(Operator.ID, query); } DBObject dbo = new BasicDBObject(key, value); WriteResult wr = coll.updateMulti(query, new BasicDBObject(Operator.INC, dbo)); if (luceneListener != null) { for (Object id : ids) { BuguEntity entity = (BuguEntity) findOne(id.toString()); luceneListener.entityUpdate(entity); } } return wr; } /** * 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 be added * @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 be addes * @return */ public WriteResult push(String id, String key, Object value) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } else if (FieldsCache.getInstance().isEmbedListField(clazz, key)) { value = MapperUtil.toDBObject(value); } DBObject query = new BasicDBObject(key, value); DBObject push = new BasicDBObject(Operator.PUSH, query); if (luceneListener != null && IndexChecker.hasIndexAnnotation(clazz, key)) { return update(id, push); } else { return updateWithOutIndex(id, push); } } /** * 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 be removed * @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 be removed * @return */ public WriteResult pull(String id, String key, Object value) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } else if (FieldsCache.getInstance().isEmbedListField(clazz, key)) { value = MapperUtil.toDBObject(value); } DBObject query = new BasicDBObject(key, value); DBObject pull = new BasicDBObject(Operator.PULL, query); if (luceneListener != null && IndexChecker.hasIndexAnnotation(clazz, key)) { return update(id, pull); } else { return updateWithOutIndex(id, pull); } } /** * Check if any entity match the condition. * * @param key the condition field * @param value the condition value * @return */ public boolean exists(String key, Object value) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } DBObject query = new BasicDBObject(key, value); return coll.findOne(query) != null; } public 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); } public T findOne(String key, Object value) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } return findOne(new BasicDBObject(key, value)); } public T findOne(DBObject query) { DBObject dbo = coll.findOne(query); return MapperUtil.fromDBObject(clazz, dbo); } public List<T> findAll() { DBCursor cursor = coll.find(new BasicDBObject(), keys); return MapperUtil.toList(clazz, cursor); } public List<T> findAll(String orderBy) { return findAll(MapperUtil.getSort(orderBy)); } public List<T> findAll(DBObject orderBy) { DBCursor cursor = coll.find(new BasicDBObject(), keys).sort(orderBy); return MapperUtil.toList(clazz, cursor); } public List<T> findAll(int pageNum, int pageSize) { DBCursor cursor = coll.find(new BasicDBObject(), keys).skip((pageNum - 1) * pageSize).limit(pageSize); return MapperUtil.toList(clazz, cursor); } public List<T> findAll(String orderBy, int pageNum, int pageSize) { return findAll(MapperUtil.getSort(orderBy), pageNum, pageSize); } public List<T> findAll(DBObject orderBy, int pageNum, int pageSize) { DBCursor cursor = coll.find(new BasicDBObject(), keys).sort(orderBy).skip((pageNum - 1) * pageSize).limit(pageSize); return MapperUtil.toList(clazz, cursor); } public List<T> find(String key, Object value) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } return find(new BasicDBObject(key, value)); } public List<T> find(DBObject query) { DBCursor cursor = coll.find(query, keys); return MapperUtil.toList(clazz, cursor); } public List<T> find(String key, Object value, String orderBy) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } return find(new BasicDBObject(key, value), MapperUtil.getSort(orderBy)); } public List<T> find(DBObject query, String orderBy) { return find(query, MapperUtil.getSort(orderBy)); } public List<T> find(DBObject query, DBObject orderBy) { DBCursor cursor = coll.find(query, keys).sort(orderBy); return MapperUtil.toList(clazz, cursor); } public List<T> find(String key, Object value, int pageNum, int pageSize) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } return find(new BasicDBObject(key, value), pageNum, pageSize); } public List<T> find(DBObject query, int pageNum, int pageSize) { DBCursor cursor = coll.find(query, keys).skip((pageNum - 1) * pageSize).limit(pageSize); return MapperUtil.toList(clazz, cursor); } public List<T> find(String key, Object value, String orderBy, int pageNum, int pageSize) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } return find(new BasicDBObject(key, value), MapperUtil.getSort(orderBy), pageNum, pageSize); } public List<T> find(DBObject query, String orderBy, int pageNum, int pageSize) { return find(query, MapperUtil.getSort(orderBy), pageNum, pageSize); } public List<T> find(DBObject query, DBObject orderBy, int pageNum, int pageSize) { DBCursor cursor = coll.find(query, keys).sort(orderBy).skip((pageNum - 1) * pageSize).limit(pageSize); return MapperUtil.toList(clazz, cursor); } public List distinct(String key) { return coll.distinct(key); } public List distinct(String key, DBObject query) { return coll.distinct(key, query); } /** * Count all entity. * * @return */ public long count() { return coll.count(); } /** * Count by condition. * * @param key the condition field * @param value the condition value * @return */ public long count(String key, Object value) { if (value instanceof BuguEntity) { BuguEntity be = (BuguEntity) value; value = ReferenceUtil.toDbReference(clazz, key, be.getClass(), be.getId()); } return count(new BasicDBObject(key, value)); } /** * Count by condition * * @param query the condition * @return */ public long count(DBObject query) { return coll.count(query); } /** * Get the DBCollection object, supplied by the mongodb java driver. * * @return */ public DBCollection getCollection() { return coll; } /** * Create a query. * * @return a new BuguQuery object */ public BuguQuery<T> query() { return new BuguQuery<T>(coll, clazz, keys); } }