From e416b0eca9ecc167370e3c4c0f4d98bb75b14329 Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Fri, 21 Aug 2015 09:01:12 -0700 Subject: [PATCH 01/20] Updated gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 54b685e..fb4f905 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ target/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + +/.classpath +/.project +/.settings/ From b4e53b4500e71ac2144e5542077a7c3014607ad9 Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Fri, 21 Aug 2015 17:15:31 -0700 Subject: [PATCH 02/20] Work on making ChangeWatchers more generic --- .../agents/sync/access/AccessManager.java | 28 ++ .../agents/sync/access/IAccessManager.java | 4 + .../sync/access/RedisAccessManager.java | 113 +++-- .../agents/sync/cw/ChangeWatcherHelper.java | 407 +--------------- .../sync/cw/ChangeWatcherHelperFactory.java | 17 +- .../sync/cw/ChangeWatcherReporting.java | 2 + .../cw/DerivedValueChangeWatcherHelper.java | 443 ++++++++++++++++++ .../agents/sync/cw/IChangeWatcherHelper.java | 17 +- .../sync/cw/IChangeWatcherHelperFactory.java | 1 + .../sync/cw/IChangeWatcherValueHelper.java | 12 + .../agents/sync/helpers/PostPutHelper.java | 2 +- .../sync/services/ISyncAgentService.java | 2 +- .../sync/services/SyncAgentService.java | 12 +- .../handlers/GetChangeWatcherHandler.java | 2 +- 14 files changed, 615 insertions(+), 447 deletions(-) create mode 100644 src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java create mode 100644 src/main/java/com/percero/agents/sync/cw/IChangeWatcherValueHelper.java diff --git a/src/main/java/com/percero/agents/sync/access/AccessManager.java b/src/main/java/com/percero/agents/sync/access/AccessManager.java index 33b1fae..77440c0 100644 --- a/src/main/java/com/percero/agents/sync/access/AccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/AccessManager.java @@ -1257,6 +1257,34 @@ public String validateAndRetrieveCurrentClientId(String clientId, return null; } + @Override + public void updateWatcherFields(String category, String subCategory, + String fieldName, Collection fieldsToWatch, String[] params) { + // TODO Auto-generated method stub + + } + + @Override + public void addWatcherField(String category, String subCategory, + String fieldName, Collection collection, String[] params) { + // TODO Auto-generated method stub + + } + + @Override + public void addWatcherField(String category, String subCategory, + String fieldName, Collection collection) { + // TODO Auto-generated method stub + + } + + @Override + public void updateWatcherFields(String category, String subCategory, + String fieldName, Collection fieldsToWatch) { + // TODO Auto-generated method stub + + } + /* (non-Javadoc) * @see com.com.percero.agents.sync.services.IAccessManager#removeDeleteJournals(java.util.List) * diff --git a/src/main/java/com/percero/agents/sync/access/IAccessManager.java b/src/main/java/com/percero/agents/sync/access/IAccessManager.java index 7875993..0a20947 100644 --- a/src/main/java/com/percero/agents/sync/access/IAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/IAccessManager.java @@ -196,10 +196,14 @@ public Set findClientByUserIdDeviceId(String deviceId, String userId) //////////////////////////////////////////////////////// public void addWatcherField(ClassIDPair classIdPair, String fieldName, Collection collection); public void addWatcherField(ClassIDPair classIdPair, String fieldName, Collection collection, String[] params); + public void addWatcherField(String category, String subCategory, String fieldName, Collection collection); + public void addWatcherField(String category, String subCategory, String fieldName, Collection collection, String[] params); public void addWatcherClient(ClassIDPair classIdPair, String fieldName, String clientId); public void addWatcherClient(ClassIDPair classIdPair, String fieldName, String clientId, String[] params); public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Collection fieldsToWatch); public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Collection fieldsToWatch, String[] params); + public void updateWatcherFields(String category, String subCategory, String fieldName, Collection fieldsToWatch); + public void updateWatcherFields(String category, String subCategory, String fieldName, Collection fieldsToWatch, String[] params); public void saveChangeWatcherResult(ClassIDPair classIdPair, String fieldName, Object result); public void saveChangeWatcherResult(ClassIDPair classIdPair, String fieldName, Object result, String[] params); public Boolean getChangeWatcherResultExists(ClassIDPair classIdPair, String fieldName); diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index cdcc43b..14ad62b 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -468,7 +468,6 @@ public void logoutClient(String clientId, Boolean pleaseDestroyClient) { } } - @Override @Transactional public void destroyClient(String clientId) { if (!StringUtils.hasText(clientId)) { @@ -1012,11 +1011,17 @@ public void addWatcherField(ClassIDPair classIdPair, String fieldName, Collectio addWatcherField(classIdPair, fieldName, collection, null); } public void addWatcherField(ClassIDPair classIdPair, String fieldName, Collection collection, String[] params) { + addWatcherField(classIdPair.getClassName(), classIdPair.getID(), fieldName, collection, params); + } + public void addWatcherField(String category, String subCategory, String fieldName, Collection collection) { + addWatcherField(category, subCategory, fieldName, collection, null); + } + public void addWatcherField(String category, String subCategory, String fieldName, Collection collection, String[] params) { String fieldWatcherId = ""; if (params != null) - fieldWatcherId = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), classIdPair.getID(), fieldName, params)); + fieldWatcherId = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(category, subCategory, fieldName, params)); else - fieldWatcherId = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), fieldName)); + fieldWatcherId = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(category, subCategory, fieldName)); if (collection != null) collection.add(fieldWatcherId); } @@ -1044,17 +1049,25 @@ public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Colle updateWatcherFields(classIdPair, fieldName, fieldsToWatch, null); } + public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Collection fieldsToWatch, String[] params) { + updateWatcherFields(classIdPair.getClassName(), classIdPair.getID(), fieldName, fieldsToWatch, params); + } + + public void updateWatcherFields(String category, String subCategory, String fieldName, Collection fieldsToWatch) { + updateWatcherFields(category, subCategory, fieldName, fieldsToWatch, null); + } + @SuppressWarnings("unchecked") @Transactional - public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Collection fieldsToWatch, String[] params) { + public void updateWatcherFields(String category, String subCategory, String fieldName, Collection fieldsToWatch, String[] params) { String changeWatcherId = ""; String watcherField = ""; if (params != null) { - changeWatcherId = RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), classIdPair.getID(), fieldName, params); - watcherField = RedisKeyUtils.watcherField(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), fieldName)); + changeWatcherId = RedisKeyUtils.changeWatcherWithParams(category, subCategory, fieldName, params); + watcherField = RedisKeyUtils.watcherField(RedisKeyUtils.changeWatcher(category, subCategory, fieldName)); } else { - changeWatcherId = RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), fieldName); + changeWatcherId = RedisKeyUtils.changeWatcher(category, subCategory, fieldName); watcherField = RedisKeyUtils.watcherField(changeWatcherId); } @@ -1113,19 +1126,22 @@ public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Colle } } - @SuppressWarnings("unchecked") public void removeChangeWatchersByObject(ClassIDPair classIdPair) { - String classKey = RedisKeyUtils.changeWatcherClass(classIdPair.getClassName(), classIdPair.getID()); + removeChangeWatchers(classIdPair.getClassName(), classIdPair.getID()); + } + @SuppressWarnings("unchecked") + public void removeChangeWatchers(String category, String subCategory) { + String categoryKey = RedisKeyUtils.changeWatcherClass(category, subCategory); // Get all change watcher values associated with this object. - Set changeWatcherValueKeys = redisDataStore.getHashKeys(classKey); + Set changeWatcherValueKeys = redisDataStore.getHashKeys(categoryKey); Iterator itrChangeWatcherValueKeys = changeWatcherValueKeys.iterator(); while (itrChangeWatcherValueKeys.hasNext()) { String nextChangeWatcherValueKey = (String) itrChangeWatcherValueKeys.next(); // If this is a RESULT key, then add it to the list to check. if (nextChangeWatcherValueKey.endsWith(":" + RedisKeyUtils.RESULT)) { int resultIndex = nextChangeWatcherValueKey.lastIndexOf(":" + RedisKeyUtils.RESULT); - String changeWatcherKey = classKey + ":" + nextChangeWatcherValueKey.substring(0, resultIndex); + String changeWatcherKey = categoryKey + ":" + nextChangeWatcherValueKey.substring(0, resultIndex); String key = changeWatcherKey; String clientWatcherKey = RedisKeyUtils.clientWatcher(changeWatcherKey); @@ -1150,7 +1166,7 @@ public void removeChangeWatchersByObject(ClassIDPair classIdPair) { } } - String objectWatchedFieldKey = RedisKeyUtils.objectWatchedFields(classIdPair.getClassName(), classIdPair.getID()); + String objectWatchedFieldKey = RedisKeyUtils.objectWatchedFields(category, subCategory); Set objectWatcherValueKeys = redisDataStore.getHashKeys(objectWatchedFieldKey); Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); while (itrObjectWatcherValueKeys.hasNext()) { @@ -1162,7 +1178,7 @@ public void removeChangeWatchersByObject(ClassIDPair classIdPair) { } redisDataStore.deleteKey(objectWatchedFieldKey); // Removes ALL change watcher values for this Object. - redisDataStore.deleteKey(classKey); // Removes ALL change watcher values for this Object. + redisDataStore.deleteKey(categoryKey); // Removes ALL change watcher values for this Object. } public void saveChangeWatcherResult(ClassIDPair classIdPair, String fieldName, Object result) { @@ -1306,15 +1322,39 @@ protected Collection getChangeWatchersForField(ClassIDPair classIdPair, } else { String fieldWatcherKey = ""; - if (params != null) + // Also add for ALL objects of this class type + String allClassObjectsFieldWatcherKey = ""; + if (params != null) { fieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), classIdPair.getID(), fieldName, params)); - else + allClassObjectsFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), "0", fieldName, params)); + } + else { fieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), fieldName)); + allClassObjectsFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), "0", fieldName)); + } + fieldWatcherKeys.add(fieldWatcherKey); + fieldWatcherKeys.add(allClassObjectsFieldWatcherKey); } } } + // Also add for this object of this class type with NO field name + String noFieldWatcherKey = ""; + // Also add for ALL objects of this class type with NO field name + String allClassObjectsNoFieldWatcherKey = ""; + if (params != null) { + noFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), classIdPair.getID(), "", params)); + allClassObjectsNoFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), "0", "", params)); + } + else { + noFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), "")); + allClassObjectsNoFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), "0", "")); + } + + fieldWatcherKeys.add(noFieldWatcherKey); + fieldWatcherKeys.add(allClassObjectsNoFieldWatcherKey); + Collection changeWatchers = null; if (fieldWatcherKeys.size() > 0) { changeWatchers = (Set) redisDataStore.getSetUnion(null, fieldWatcherKeys); @@ -1327,14 +1367,22 @@ protected Set getAllFieldWatchersForObject(ClassIDPair classIdPair) { Set fieldWatcherKeys = new HashSet(); String objectWatchedFieldKey = RedisKeyUtils.objectWatchedFields(classIdPair.getClassName(), classIdPair.getID()); - Set objectWatcherValueKeys = redisDataStore.getHashKeys(objectWatchedFieldKey); - Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); - while (itrObjectWatcherValueKeys.hasNext()) { - String nextObjectWatcherValueKey = (String) itrObjectWatcherValueKeys.next(); + // Also add for ALL objects of this class type + String allObjectsWatchedFieldKey = RedisKeyUtils.objectWatchedFields(classIdPair.getClassName(), "0"); - // Get all fields for this object that are being watched and remove them. - String changeWatcherKey = (String) redisDataStore.getHashValue(objectWatchedFieldKey, nextObjectWatcherValueKey); - fieldWatcherKeys.add(changeWatcherKey); + String[] fieldKeys = {objectWatchedFieldKey, allObjectsWatchedFieldKey}; + + for(int i=0; i objectWatcherValueKeys = redisDataStore.getHashKeys(nextKey); + Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); + while (itrObjectWatcherValueKeys.hasNext()) { + String nextObjectWatcherValueKey = (String) itrObjectWatcherValueKeys.next(); + + // Get all fields for this object that are being watched and remove them. + String changeWatcherKey = (String) redisDataStore.getHashValue(nextKey, nextObjectWatcherValueKey); + fieldWatcherKeys.add(changeWatcherKey); + } } return fieldWatcherKeys; @@ -1399,11 +1447,11 @@ public void recalculateChangeWatcher(String changeWatcherId) { // Need to break up String[] params = changeWatcherId.split(":"); - // 3rd var should be class name. - String className = params[2]; + // 3rd var should be category. + String category = params[2]; - // 4th var should be classId. - String classId = params[3]; + // 4th var should be subCategory. + String subCategory = params[3]; // 5th var should be fieldName. String fieldName = params[4]; @@ -1419,10 +1467,17 @@ public void recalculateChangeWatcher(String changeWatcherId) { if (changeWatcherHelperFactory != null) { Collection clientIds = (Set) redisDataStore.getSetValue(RedisKeyUtils.clientWatcher(changeWatcherId)); // The list of ClientID's who are interested in this object. - ClassIDPair pair = new ClassIDPair(classId, className); + + IChangeWatcherHelper cwh = changeWatcherHelperFactory.getHelper(category); + cwh.reprocess(category, subCategory, fieldName, clientIds, otherParams, requestTimestamp); - IChangeWatcherHelper cwh = changeWatcherHelperFactory.getHelper(className); - cwh.recalculate(fieldName, pair, clientIds, otherParams, requestTimestamp); +// // If this is an Object Change Watcher, then build a ClassIDPair and run the recalc. +// if (false) { +// ClassIDPair pair = new ClassIDPair(subCategory, category); +// cwh.recalculate(fieldName, pair, clientIds, otherParams, requestTimestamp); +// } +// else { +// } /** // If no clients interested in this value, then remove it from the cache. if (clientIds == null || clientIds.isEmpty()) { diff --git a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java index 249e9cf..4329eee 100644 --- a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java +++ b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java @@ -1,48 +1,32 @@ package com.percero.agents.sync.cw; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import org.apache.log4j.Logger; -import org.codehaus.jackson.map.ObjectMapper; -import org.joda.time.DateTime; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; import com.mchange.v2.lang.ObjectUtils; import com.percero.agents.sync.access.IAccessManager; -import com.percero.agents.sync.hibernate.SyncHibernateUtils; -import com.percero.agents.sync.metadata.IMappedClassManager; -import com.percero.agents.sync.metadata.MappedClass; -import com.percero.agents.sync.metadata.MappedClassManagerFactory; -import com.percero.agents.sync.services.IDataProvider; -import com.percero.agents.sync.services.IDataProviderManager; -import com.percero.agents.sync.services.IPushSyncHelper; -import com.percero.agents.sync.services.ISyncAgentService; import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.ClassIDPair; -import com.percero.agents.sync.vo.IClassIDPair; -import com.percero.agents.sync.vo.PushCWUpdateResponse; import com.percero.framework.vo.IPerceroObject; +/** + * ChangeWatcherHelper allows code to be executed upon the change of any model data. The ChangeWatcherHelper is used + * as the mechanism to execute that code. A ChangeWatcherHelper must be registered with the ChangeWatcherHelperFactory. + * Ex: ChangeWatcherHelperFactory.getInstance().registerChangeWatcherHelper( "category", this ); + * + * @author Collin Brown + * + */ @Component public class ChangeWatcherHelper implements IChangeWatcherHelper { private static final Logger log = Logger.getLogger(ChangeWatcherHelper.class); - @Autowired - ObjectMapper objectMapper; - -// @Scheduled(fixedRate=10000) -// public void printStats() { -// log.debug(ChangeWatcherReporting.stringResults()); -// } @Autowired protected IAccessManager accessManager; @@ -50,386 +34,29 @@ public void setAccessManager(IAccessManager value) { accessManager = value; } - @Autowired - protected IDataProviderManager dataProviderManager; - public void setDataProviderManager(IDataProviderManager value) { - dataProviderManager = value; - } - public IDataProviderManager getDataProviderManager() { - return dataProviderManager; - } - - @Autowired - protected ISyncAgentService syncAgentService; - public void setSyncAgentService(ISyncAgentService value) { - syncAgentService = value; - } - public ISyncAgentService getSyncAgentService() { - return syncAgentService; - } - - @Autowired - protected IPushSyncHelper pushSyncHelper; - public void setPushSyncHelper(IPushSyncHelper value) { - pushSyncHelper = value; - } - - - public Object get(String fieldName, ClassIDPair classIdPair) { - return get(fieldName, classIdPair, null, null); - } - - public Object get(String fieldName, ClassIDPair classIdPair, String clientId) { - return get(fieldName, classIdPair, null, clientId); - } - - - public Object get(String fieldName, ClassIDPair classIdPair, String[] params) { - return get(fieldName, classIdPair, params, null); - } - - public Object get(String fieldName, ClassIDPair classIdPair, String[] params, String clientId) { - Object result = null; - try { - // Make sure this being requested by a valid person. - if (StringUtils.hasText(clientId)) { - String userId = accessManager.getClientUserId(clientId); - if (!StringUtils.hasLength(userId)) { - log.warn("Invalid clientId in get: " + fieldName); - return result; - } - } - - // Check to see if this value has already been calculated. - Boolean resultExists = accessManager.getChangeWatcherResultExists(classIdPair, fieldName, params); - - if (resultExists) { -// Long resultTimestamp = accessManager.getChangeWatcherResultTimestamp(classIdPair, fieldName, params); - result = accessManager.getChangeWatcherResult(classIdPair, fieldName, params); - } - else { - // Result has not been calculated, so need to calculate. - result = calculate(fieldName, classIdPair, params); - } - - if (StringUtils.hasText(clientId)) { - result = getForClient(fieldName, classIdPair, params, result, clientId); - accessManager.addWatcherClient(classIdPair, fieldName, clientId, params); - } - } catch(Exception e) { - log.error("Unable to get " + fieldName, e); - } - - return result; - } - - @SuppressWarnings("rawtypes") - protected Object getForClient(String fieldName, ClassIDPair classIdPair, String[] params, Object result, String clientId) { - - String userId = accessManager.getClientUserId(clientId); - - if (result instanceof IPerceroObject) { - if (validateReadAccess((BaseDataObject) result, userId)) - return result; - else - return null; - } - if (result instanceof IClassIDPair) { - if (validateReadAccess((ClassIDPair) result, userId)) - return result; - else - return null; - } - else if (result instanceof Collection) { - Iterator itr = ((Collection) result).iterator(); - while(itr.hasNext()) { - Object next = itr.next(); - - if (next instanceof IPerceroObject) { - if (!validateReadAccess((BaseDataObject) next, userId)) { - itr.remove(); - } - } - else if (next instanceof IClassIDPair) { - if (!validateReadAccess((ClassIDPair) next, userId)) { - itr.remove(); - } - } - } - - return result; - } - else { - return result; - } - } - - protected Boolean validateReadAccess(BaseDataObject bdo, String userId) { - return validateReadAccess(new ClassIDPair(bdo.getID(), bdo.getClass().getCanonicalName()), userId); - } - - protected Boolean validateReadAccess(ClassIDPair classIdPair, String userId) { - String className = classIdPair.getClassName(); - String id = classIdPair.getID(); - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(className); - Boolean hasAccess = true; - - if (mappedClass != null) { - IDataProviderManager dataProviderManager = getDataProviderManager(); - - IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - hasAccess = dataProvider.getReadAccess(new ClassIDPair(id, className), userId); - } - - if (hasAccess) - return true; - else - return false; - } - - public Object calculate(String fieldName, ClassIDPair classIdPair) { - return null; + public void process(String category, String subCategory, String fieldName) { + // This is really an error. + StringBuilder strBuilder = new StringBuilder("No value calculate method found for: ").append(category).append(":").append(subCategory).append(":").append(fieldName); + log.error(strBuilder.toString()); } - public Object calculate(String fieldName, ClassIDPair classIdPair, String[] params) { + public void process(String category, String subCategory, String fieldName, String[] params) { // This is really an error. - StringBuilder strBuilder = new StringBuilder("No value calculate method found for: ").append(classIdPair.getClassName()).append(":").append(fieldName); + StringBuilder strBuilder = new StringBuilder("No value process method found for: ").append(category).append(":").append(subCategory).append(":").append(fieldName); for(String nextString : params) { strBuilder.append(".").append(nextString); } log.error(strBuilder.toString()); - return null; - } - - /**protected void postCalculate(String fieldName, ClassIDPair classIdPair, Object result, Object oldValue) { - postCalculate(fieldName, classIdPair, result, null); - }*/ - private Map changeWatcherResults = new HashMap(); - protected void postCalculate(String fieldName, ClassIDPair classIdPair, String[] params, Object result, Object oldValue) { - // Now run past the ChangeWatcher. - try { - String cwResultKey = fieldName + classIdPair.toString() + (params == null ? "" : params.toString()); - ChangeWatcherResult cwResult = changeWatcherResults.get(cwResultKey); - if (cwResult == null) { - cwResult = new ChangeWatcherResult(oldValue, result, eqOrBothNull(oldValue, result)); - } - else { - cwResult.setNewValue(result); - cwResult.setEqOrBothNull(eqOrBothNull(oldValue, result)); - } - - // Check to see if this value has already been calculated. - if (cwResult.getEqOrBothNull()) { - ChangeWatcherReporting.unchangedResultsCounter++; -// log.debug("Object has not changed, so not checking ChangeWatchers."); - } - else { - ChangeWatcherReporting.changedResultsCounter++; - String[] fieldNames = null; - if (StringUtils.hasText(fieldName)) { - fieldNames = new String[1]; - fieldNames[0] = fieldName; - } - accessManager.checkChangeWatchers(classIdPair, fieldNames, params); - } - } catch (Exception e) { - log.error("Unable to chech change watchers for " + classIdPair.getID() + " / " + fieldName + " in " + getClass().getCanonicalName()); - } } - public void recalculate(String fieldName, ClassIDPair classIdPair, Collection clientIds, String[] params, Long requestTimestamp) { - Object value = null; - - // Check to see if this value has already been calculated. - Object currentValue = null; - ChangeWatcherReporting.recalcsCounter++; - try { - if (requestTimestamp != null) { - Long resultTimestamp = accessManager.getChangeWatcherResultTimestamp(classIdPair, fieldName, params); - if (resultTimestamp != null && resultTimestamp.compareTo(requestTimestamp) > 0) { - // If the result timestamp is after the request timestamp, then no need to recalculate. - // In essence, the recalc was already done, albeit at the behest of another process. - ChangeWatcherReporting.abortedRecalcsCounter++; -// log.debug("Aborting ChangeWatcherHelper.recalculate request since it has already been fulfilled."); - return; - } - } - currentValue = accessManager.getChangeWatcherResult(classIdPair, fieldName, params); - } catch(Exception e) {} - - - String cwResultKey = fieldName + classIdPair.toString() + (params == null ? "" : params.toString()); - ChangeWatcherResult cwResult = new ChangeWatcherResult(currentValue); - changeWatcherResults.put(cwResultKey, cwResult); - - // TODO: Pass the ChangeWatcherResult to calculate so that we don't have to retrieve the current value twice. - value = calculate(fieldName, classIdPair, params); - changeWatcherResults.remove(cwResultKey); - - if (!cwResult.getEqOrBothNull()) { -// ChangeWatcherReporting.unchangedResultsCounter++; - log.debug("Object has changed, pushing update."); - pushUpdate(classIdPair, fieldName, params, value, clientIds); - } + public void reprocess(String category, String subCategory, String fieldName, Collection clientIds, String[] params, Long requestTimestamp) { + ChangeWatcherReporting.reprocessCounter++; + process(category, subCategory, fieldName, params); log.debug(ChangeWatcherReporting.stringResults()); } - - protected void pushUpdate(ClassIDPair classIdPair, String fieldName, String[] params, Object update, Collection clientIds) { - // Now push the result to all interested clients. - try { - Iterator itrClientIds = clientIds.iterator(); - while(itrClientIds.hasNext()) { - String nextClient = itrClientIds.next(); - Object nextUpdate = getForClient(fieldName, classIdPair, params, update, nextClient); - pushChangeWatcherUpdate(nextClient, classIdPair, fieldName, params, nextUpdate); - } - } catch(Exception e) { - log.error("Unable to pushUpdate", e); - } - } - - - public void pushChangeWatcherUpdate(Collection clientIds, ClassIDPair classIdPair, String fieldName, String[] params, Object value) { - if (clientIds != null && clientIds.size() > 0) { - try { - PushCWUpdateResponse pushUpdateResponse = new PushCWUpdateResponse(); - pushUpdateResponse.setFieldName(fieldName); - pushUpdateResponse.setParams(params); - pushUpdateResponse.setClassIdPair(classIdPair); - - for(Object nextClient : clientIds) { - - String clientId = (String) nextClient; - if (!StringUtils.hasLength(clientId)) - continue; - - //if (value instanceof BaseDataObject) { - String userId = accessManager.getClientUserId(clientId); - // Clean the value if it is a framework object. - value = SyncHibernateUtils.cleanObject(value, null, userId); - //} - pushUpdateResponse.setValue(value); - pushUpdateResponse.setClientId(clientId); - - pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, clientId); - } - - } catch(Exception e) { - log.error("Error sending ChangeWatcher Updates to clients", e); - } - } - } - public void pushChangeWatcherUpdate(String clientId, ClassIDPair classIdPair, String fieldName, String[] params, Object value) { - if (StringUtils.hasText(clientId)) { - try { - PushCWUpdateResponse pushUpdateResponse = new PushCWUpdateResponse(); - pushUpdateResponse.setFieldName(fieldName); - pushUpdateResponse.setParams(params); - pushUpdateResponse.setClassIdPair(classIdPair); - - if (value instanceof IPerceroObject) { - String userId = accessManager.getClientUserId(clientId); - // Clean the value if it is a framework object. - value = (BaseDataObject) SyncHibernateUtils.cleanObject(value, null, userId); - } - pushUpdateResponse.setValue(value); - - pushUpdateResponse.setClientId(clientId); - - pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, clientId); - - } catch(Exception e) { - log.error("Error sending ChangeWatcher Updates to clients", e); - } - } - } - - /**************************** - * HELPER FUNCTIONS - ****************************/ - public DateTime parseDateTime(String theDate) { - String testDate = theDate.replace('_', ' '); - DateTime dateTime = null; - if (dateTime == null) { - try { - dateTime = new DateTime(Long.parseLong(theDate)); - } catch(IllegalArgumentException e) { - // Possibly the wrong format date, try a different format. - } - } - - //testDate = "2013-10-01 +07:00"; - DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ZZ"); - if (dateTime == null) { - try { - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss Z"); - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ZZZ"); - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); - dateTime = formatter.parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd ZZZ"); - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd ZZ"); - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd Z"); - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd"); - dateTime = formatter.parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - - return dateTime; - } @SuppressWarnings("unchecked") public static boolean eqOrBothNull(Object resultA, Object resultB) { diff --git a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelperFactory.java b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelperFactory.java index cbe6c2e..8783440 100644 --- a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelperFactory.java +++ b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelperFactory.java @@ -34,16 +34,23 @@ public static IChangeWatcherHelperFactory getInstance() { public ChangeWatcherHelperFactory() { currentInstance = this; } + + public void registerChangeWatcherHelper(String category, IChangeWatcherHelper changeWatcherHelper) { + IChangeWatcherHelper existingHelper = helperCache.get(category); + if (existingHelper == null) { + helperCache.put(category, changeWatcherHelper); + } + } private Map helperCache = new HashMap(); @SuppressWarnings({ "rawtypes", "unchecked" }) - public IChangeWatcherHelper getHelper(String className) { - IChangeWatcherHelper helper = helperCache.get(className); + public IChangeWatcherHelper getHelper(String category) { + IChangeWatcherHelper helper = helperCache.get(category); if (helper == null) { // Get the appropriate Helper Component. try { - Class clazz = MappedClass.forName(className); + Class clazz = MappedClass.forName(category); while (clazz != null) { try { // Get the class name only. @@ -55,7 +62,7 @@ public IChangeWatcherHelper getHelper(String className) { //String helperClassName = (new StringBuilder(className).append("CWHelper")).toString(); helper = (IChangeWatcherHelper) context.getBean(StringUtils.uncapitalize(theClassName) + "CWHelper", MappedClass.forName(helperClassName)); if (helper != null) { - helperCache.put(className, helper); + helperCache.put(category, helper); return helper; } } catch(Exception e) { @@ -65,7 +72,7 @@ public IChangeWatcherHelper getHelper(String className) { clazz = clazz.getSuperclass(); } } catch(Exception e) { - log.error("Unable to get ChangeWatcherHelper for " + className, e); + log.error("Unable to get ChangeWatcherHelper for " + category, e); } return null; diff --git a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherReporting.java b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherReporting.java index a460b89..09e3bd0 100644 --- a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherReporting.java +++ b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherReporting.java @@ -7,6 +7,7 @@ public class ChangeWatcherReporting { public static Integer recalcsCounter = 0; public static Integer abortedRecalcsCounter = 0; + public static Integer reprocessCounter = 0; public static Integer unchangedResultsCounter = 0; public static Integer changedResultsCounter = 0; @@ -17,6 +18,7 @@ public static String stringResults() { result.append("Internal Requests: ").append(internalRequestsCounter).append("\n"); result.append("Unchanged Results: ").append(unchangedResultsCounter).append("\n"); result.append("Changed Results: ").append(changedResultsCounter).append("\n"); + result.append("Reprocess: ").append(reprocessCounter).append("\n"); result.append("Recalcs: ").append(recalcsCounter).append("\n"); result.append("Aborted Recalcs: ").append(abortedRecalcsCounter).append("\n"); result.append("Aborted %: ").append((100.0 * abortedRecalcsCounter / recalcsCounter)).append("\n"); diff --git a/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java b/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java new file mode 100644 index 0000000..5340a5f --- /dev/null +++ b/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java @@ -0,0 +1,443 @@ +package com.percero.agents.sync.cw; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import com.percero.agents.sync.access.IAccessManager; +import com.percero.agents.sync.hibernate.SyncHibernateUtils; +import com.percero.agents.sync.metadata.IMappedClassManager; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClassManagerFactory; +import com.percero.agents.sync.services.IDataProvider; +import com.percero.agents.sync.services.IDataProviderManager; +import com.percero.agents.sync.services.IPushSyncHelper; +import com.percero.agents.sync.services.ISyncAgentService; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.agents.sync.vo.ClassIDPair; +import com.percero.agents.sync.vo.IClassIDPair; +import com.percero.agents.sync.vo.PushCWUpdateResponse; +import com.percero.framework.vo.IPerceroObject; + +@Component +public class DerivedValueChangeWatcherHelper extends ChangeWatcherHelper implements IChangeWatcherValueHelper { + + private static final Logger log = Logger.getLogger(ChangeWatcherHelper.class); + +// @Autowired +// ObjectMapper objectMapper; + + @Autowired + protected IPushSyncHelper pushSyncHelper; + public void setPushSyncHelper(IPushSyncHelper value) { + pushSyncHelper = value; + } + + @Autowired + protected IDataProviderManager dataProviderManager; + public void setDataProviderManager(IDataProviderManager value) { + dataProviderManager = value; + } + public IDataProviderManager getDataProviderManager() { + return dataProviderManager; + } + + @Autowired + protected ISyncAgentService syncAgentService; + public void setSyncAgentService(ISyncAgentService value) { + syncAgentService = value; + } + public ISyncAgentService getSyncAgentService() { + return syncAgentService; + } + + + public Object calculate(String fieldName, ClassIDPair classIdPair) { + // This is really an error. + StringBuilder strBuilder = new StringBuilder("No value calculate method found for: ").append(classIdPair.getClassName()).append(":").append(fieldName); + log.error(strBuilder.toString()); + return null; + } + + public Object calculate(String fieldName, ClassIDPair classIdPair, String[] params) { + // This is really an error. + StringBuilder strBuilder = new StringBuilder("No value calculate method found for: ").append(classIdPair.getClassName()).append(":").append(fieldName); + for(String nextString : params) { + strBuilder.append(".").append(nextString); + } + log.error(strBuilder.toString()); + return null; + } + + @Override + public void process(String category, String subCategory, String fieldName) { + calculate(fieldName, new ClassIDPair(subCategory, category)); + } + + @Override + public void process(String category, String subCategory, String fieldName, String[] params) { + calculate(fieldName, new ClassIDPair(subCategory, category), params); + } + + /**protected void postCalculate(String fieldName, ClassIDPair classIdPair, Object result, Object oldValue) { + postCalculate(fieldName, classIdPair, result, null); + }*/ + private Map changeWatcherResults = new HashMap(); + protected void postCalculate(String fieldName, ClassIDPair classIdPair, String[] params, Object result, Object oldValue) { + // Now run past the ChangeWatcher. + try { + String cwResultKey = fieldName + classIdPair.toString() + (params == null ? "" : params.toString()); + ChangeWatcherResult cwResult = changeWatcherResults.get(cwResultKey); + if (cwResult == null) { + cwResult = new ChangeWatcherResult(oldValue, result, eqOrBothNull(oldValue, result)); + } + else { + cwResult.setNewValue(result); + cwResult.setEqOrBothNull(eqOrBothNull(oldValue, result)); + } + + // Check to see if this value has already been calculated. + if (cwResult.getEqOrBothNull()) { + ChangeWatcherReporting.unchangedResultsCounter++; +// log.debug("Object has not changed, so not checking ChangeWatchers."); + } + else { + ChangeWatcherReporting.changedResultsCounter++; + String[] fieldNames = null; + if (StringUtils.hasText(fieldName)) { + fieldNames = new String[1]; + fieldNames[0] = fieldName; + } + accessManager.checkChangeWatchers(classIdPair, fieldNames, params); + } + } catch (Exception e) { + log.error("Unable to chech change watchers for " + classIdPair.getID() + " / " + fieldName + " in " + getClass().getCanonicalName()); + } + } + + + public void recalculate(String fieldName, ClassIDPair classIdPair, Collection clientIds, String[] params, Long requestTimestamp) { + Object value = null; + + // Check to see if this value has already been calculated. + Object currentValue = null; + ChangeWatcherReporting.recalcsCounter++; + try { + if (requestTimestamp != null) { + Long resultTimestamp = accessManager.getChangeWatcherResultTimestamp(classIdPair, fieldName, params); + if (resultTimestamp != null && resultTimestamp.compareTo(requestTimestamp) > 0) { + // If the result timestamp is after the request timestamp, then no need to recalculate. + // In essence, the recalc was already done, albeit at the behest of another process. + ChangeWatcherReporting.abortedRecalcsCounter++; +// log.debug("Aborting ChangeWatcherHelper.recalculate request since it has already been fulfilled."); + return; + } + } + currentValue = accessManager.getChangeWatcherResult(classIdPair, fieldName, params); + } catch(Exception e) {} + + + String cwResultKey = fieldName + classIdPair.toString() + (params == null ? "" : params.toString()); + ChangeWatcherResult cwResult = new ChangeWatcherResult(currentValue); + changeWatcherResults.put(cwResultKey, cwResult); + + // TODO: Pass the ChangeWatcherResult to calculate so that we don't have to retrieve the current value twice. + value = calculate(fieldName, classIdPair, params); + changeWatcherResults.remove(cwResultKey); + + if (!cwResult.getEqOrBothNull()) { +// ChangeWatcherReporting.unchangedResultsCounter++; + log.debug("Object has changed, pushing update."); + pushUpdate(classIdPair, fieldName, params, value, clientIds); + } + + log.debug(ChangeWatcherReporting.stringResults()); + } + + @Override + public void reprocess(String category, String subCategory, String fieldName, Collection clientIds, String[] params, Long requestTimestamp) { + ChangeWatcherReporting.reprocessCounter++; + this.recalculate(fieldName, new ClassIDPair(subCategory, category), clientIds, params, requestTimestamp); + } + + + + public Object get(String fieldName, ClassIDPair classIdPair) { + return get(fieldName, classIdPair, null, null); + } + + public Object get(String fieldName, ClassIDPair classIdPair, String clientId) { + return get(fieldName, classIdPair, null, clientId); + } + + + public Object get(String fieldName, ClassIDPair classIdPair, String[] params) { + return get(fieldName, classIdPair, params, null); + } + + public Object get(String fieldName, ClassIDPair classIdPair, String[] params, String clientId) { + Object result = null; + try { + // Make sure this being requested by a valid person. + if (StringUtils.hasText(clientId)) { + String userId = accessManager.getClientUserId(clientId); + if (!StringUtils.hasLength(userId)) { + log.warn("Invalid clientId in get: " + fieldName); + return result; + } + } + + // Check to see if this value has already been calculated. + Boolean resultExists = accessManager.getChangeWatcherResultExists(classIdPair, fieldName, params); + + if (resultExists) { +// Long resultTimestamp = accessManager.getChangeWatcherResultTimestamp(classIdPair, fieldName, params); + result = accessManager.getChangeWatcherResult(classIdPair, fieldName, params); + } + else { + // Result has not been calculated, so need to calculate. + result = calculate(fieldName, classIdPair, params); + } + + if (StringUtils.hasText(clientId)) { + result = getForClient(fieldName, classIdPair, params, result, clientId); + accessManager.addWatcherClient(classIdPair, fieldName, clientId, params); + } + } catch(Exception e) { + log.error("Unable to get " + fieldName, e); + } + + return result; + } + + @SuppressWarnings("rawtypes") + protected Object getForClient(String fieldName, ClassIDPair classIdPair, String[] params, Object result, String clientId) { + + String userId = accessManager.getClientUserId(clientId); + + if (result instanceof IPerceroObject) { + if (validateReadAccess((BaseDataObject) result, userId)) + return result; + else + return null; + } + if (result instanceof IClassIDPair) { + if (validateReadAccess((ClassIDPair) result, userId)) + return result; + else + return null; + } + else if (result instanceof Collection) { + Iterator itr = ((Collection) result).iterator(); + while(itr.hasNext()) { + Object next = itr.next(); + + if (next instanceof IPerceroObject) { + if (!validateReadAccess((BaseDataObject) next, userId)) { + itr.remove(); + } + } + else if (next instanceof IClassIDPair) { + if (!validateReadAccess((ClassIDPair) next, userId)) { + itr.remove(); + } + } + } + + return result; + } + else { + return result; + } + } + + protected Boolean validateReadAccess(BaseDataObject bdo, String userId) { + return validateReadAccess(new ClassIDPair(bdo.getID(), bdo.getClass().getCanonicalName()), userId); + } + + protected Boolean validateReadAccess(ClassIDPair classIdPair, String userId) { + String className = classIdPair.getClassName(); + String id = classIdPair.getID(); + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); + Boolean hasAccess = true; + + if (mappedClass != null) { + IDataProviderManager dataProviderManager = getDataProviderManager(); + + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); + hasAccess = dataProvider.getReadAccess(new ClassIDPair(id, className), userId); + } + + if (hasAccess) + return true; + else + return false; + } + + + + protected void pushUpdate(ClassIDPair classIdPair, String fieldName, String[] params, Object update, Collection clientIds) { + // Now push the result to all interested clients. + try { + Iterator itrClientIds = clientIds.iterator(); + while(itrClientIds.hasNext()) { + String nextClient = itrClientIds.next(); + Object nextUpdate = getForClient(fieldName, classIdPair, params, update, nextClient); + pushChangeWatcherUpdate(nextClient, classIdPair, fieldName, params, nextUpdate); + } + } catch(Exception e) { + log.error("Unable to pushUpdate", e); + } + } + + + public void pushChangeWatcherUpdate(Collection clientIds, ClassIDPair classIdPair, String fieldName, String[] params, Object value) { + if (clientIds != null && clientIds.size() > 0) { + try { + PushCWUpdateResponse pushUpdateResponse = new PushCWUpdateResponse(); + pushUpdateResponse.setFieldName(fieldName); + pushUpdateResponse.setParams(params); + pushUpdateResponse.setClassIdPair(classIdPair); + + for(Object nextClient : clientIds) { + + String clientId = (String) nextClient; + if (!StringUtils.hasLength(clientId)) + continue; + + //if (value instanceof BaseDataObject) { + String userId = accessManager.getClientUserId(clientId); + // Clean the value if it is a framework object. + value = SyncHibernateUtils.cleanObject(value, null, userId); + //} + pushUpdateResponse.setValue(value); + pushUpdateResponse.setClientId(clientId); + + pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, clientId); + } + + } catch(Exception e) { + log.error("Error sending ChangeWatcher Updates to clients", e); + } + } + } + public void pushChangeWatcherUpdate(String clientId, ClassIDPair classIdPair, String fieldName, String[] params, Object value) { + if (StringUtils.hasText(clientId)) { + try { + PushCWUpdateResponse pushUpdateResponse = new PushCWUpdateResponse(); + pushUpdateResponse.setFieldName(fieldName); + pushUpdateResponse.setParams(params); + pushUpdateResponse.setClassIdPair(classIdPair); + + if (value instanceof IPerceroObject) { + String userId = accessManager.getClientUserId(clientId); + // Clean the value if it is a framework object. + value = (BaseDataObject) SyncHibernateUtils.cleanObject(value, null, userId); + } + pushUpdateResponse.setValue(value); + + pushUpdateResponse.setClientId(clientId); + + pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, clientId); + + } catch(Exception e) { + log.error("Error sending ChangeWatcher Updates to clients", e); + } + } + } + + + /**************************** + * HELPER FUNCTIONS + ****************************/ + public DateTime parseDateTime(String theDate) { + String testDate = theDate.replace('_', ' '); + DateTime dateTime = null; + if (dateTime == null) { + try { + dateTime = new DateTime(Long.parseLong(theDate)); + } catch(IllegalArgumentException e) { + // Possibly the wrong format date, try a different format. + } + } + + //testDate = "2013-10-01 +07:00"; + DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ZZ"); + if (dateTime == null) { + try { + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss Z"); + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ZZZ"); + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); + dateTime = formatter.parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd ZZZ"); + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd ZZ"); + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd Z"); + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd"); + dateTime = formatter.parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + + return dateTime; + } + +} diff --git a/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelper.java b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelper.java index 650d43a..9f1a02c 100644 --- a/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelper.java +++ b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelper.java @@ -2,19 +2,10 @@ import java.util.Collection; -import com.percero.agents.sync.services.IDataProviderManager; -import com.percero.agents.sync.services.ISyncAgentService; -import com.percero.agents.sync.vo.ClassIDPair; - public interface IChangeWatcherHelper { - public ISyncAgentService getSyncAgentService(); - public IDataProviderManager getDataProviderManager(); - public Object get(String fieldName, ClassIDPair classIdPair); - public Object get(String fieldName, ClassIDPair classIdPair, String clientId); - public Object get(String fieldName, ClassIDPair classIdPair, String[] params); - public Object get(String fieldName, ClassIDPair classIdPair, String[] params, String clientId); - public Object calculate(String fieldName, ClassIDPair classIdPair); - public Object calculate(String fieldName, ClassIDPair classIdPair, String[] params); - public void recalculate(String fieldName, ClassIDPair classIdPair, Collection clientIds, String[] params, Long requestTimestamp); + public void process(String category, String subCategory, String fieldName); + public void process(String category, String subCategory, String fieldName, String[] params); + public void reprocess(String category, String subCategory, String fieldName, Collection clientIds, String[] params, Long requestTimestamp); + } diff --git a/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelperFactory.java b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelperFactory.java index 7bf0e7c..0de0907 100644 --- a/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelperFactory.java +++ b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelperFactory.java @@ -4,4 +4,5 @@ public interface IChangeWatcherHelperFactory { public IChangeWatcherHelper getHelper(String className); + public void registerChangeWatcherHelper(String category, IChangeWatcherHelper changeWatcherHelper); } diff --git a/src/main/java/com/percero/agents/sync/cw/IChangeWatcherValueHelper.java b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherValueHelper.java new file mode 100644 index 0000000..2408de2 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherValueHelper.java @@ -0,0 +1,12 @@ +package com.percero.agents.sync.cw; + +import com.percero.agents.sync.vo.ClassIDPair; + +public interface IChangeWatcherValueHelper { + + public Object get(String fieldName, ClassIDPair classIdPair); + public Object get(String fieldName, ClassIDPair classIdPair, String clientId); + public Object get(String fieldName, ClassIDPair classIdPair, String[] params); + public Object get(String fieldName, ClassIDPair classIdPair, String[] params, String clientId); + +} diff --git a/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java b/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java index 36ead6e..117877e 100644 --- a/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java @@ -84,7 +84,7 @@ public void postPutObject(ClassIDPair pair, String pusherUserId, String pusherCl // Now run past the ChangeWatcher. - if (changedFields == null) { + if (changedFields == null || changedFields.isEmpty()) { accessManager.checkChangeWatchers(pair, null, null); } else { diff --git a/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java b/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java index 69d24a8..edb4ed9 100644 --- a/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java +++ b/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java @@ -52,7 +52,7 @@ public interface ISyncAgentService { public Object findUnique(Object theQueryObject, String clientId) throws Exception; public Object runQuery(String className, String queryName, Object[] queryArguments, String clientId) throws Exception; public Object runProcess(String processName, Object[] queryArguments, String clientId) throws Exception; - public Object getChangeWatcher(ClassIDPair classIdPair, String fieldName, String[] params, String clientId) throws Exception; + public Object getChangeWatcherValue(ClassIDPair classIdPair, String fieldName, String[] params, String clientId) throws Exception; public List getHistory(String aClassName, String anId, String clientId) throws Exception; public Object searchByExample(Object theQueryObject, String clientId) throws Exception; diff --git a/src/main/java/com/percero/agents/sync/services/SyncAgentService.java b/src/main/java/com/percero/agents/sync/services/SyncAgentService.java index 120ca8e..78086fa 100644 --- a/src/main/java/com/percero/agents/sync/services/SyncAgentService.java +++ b/src/main/java/com/percero/agents/sync/services/SyncAgentService.java @@ -27,8 +27,8 @@ import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.access.RedisKeyUtils; -import com.percero.agents.sync.cw.IChangeWatcherHelper; import com.percero.agents.sync.cw.IChangeWatcherHelperFactory; +import com.percero.agents.sync.cw.IChangeWatcherValueHelper; import com.percero.agents.sync.datastore.RedisDataStore; import com.percero.agents.sync.events.SyncEvent; import com.percero.agents.sync.exceptions.ClientException; @@ -379,18 +379,16 @@ public Object runProcess(String processName, Object[] queryArguments, String cli return result; } - public Object getChangeWatcher(ClassIDPair classIdPair, String fieldName, String[] params, String clientId) throws Exception { + public Object getChangeWatcherValue(ClassIDPair classIdPair, String fieldName, String[] params, String clientId) throws Exception { Object result = null; Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); - if (changeWatcherHelperFactory != null) - { - IChangeWatcherHelper cwh = changeWatcherHelperFactory.getHelper(classIdPair.getClassName()); - result = cwh.get(fieldName, classIdPair, params, clientId); - } + // Only ChangeWatcherValueHelper's have the "get" function. + IChangeWatcherValueHelper cwh = (IChangeWatcherValueHelper) changeWatcherHelperFactory.getHelper(classIdPair.getClassName()); + result = cwh.get(fieldName, classIdPair, params, clientId); return result; } diff --git a/src/main/java/com/percero/amqp/handlers/GetChangeWatcherHandler.java b/src/main/java/com/percero/amqp/handlers/GetChangeWatcherHandler.java index 87651f9..e2020fe 100644 --- a/src/main/java/com/percero/amqp/handlers/GetChangeWatcherHandler.java +++ b/src/main/java/com/percero/amqp/handlers/GetChangeWatcherHandler.java @@ -20,7 +20,7 @@ public GetChangeWatcherHandler() { public SyncResponse handleMessage(SyncRequest request, String replyTo) throws Exception { PushCWUpdateResponse response = new PushCWUpdateResponse(); PushCWUpdateRequest pushCwUpdateRequest = (PushCWUpdateRequest) request; - Object result = syncAgentService.getChangeWatcher(pushCwUpdateRequest.getClassIdPair(), pushCwUpdateRequest.getFieldName(), pushCwUpdateRequest.getParams(), pushCwUpdateRequest.getClientId()); + Object result = syncAgentService.getChangeWatcherValue(pushCwUpdateRequest.getClassIdPair(), pushCwUpdateRequest.getFieldName(), pushCwUpdateRequest.getParams(), pushCwUpdateRequest.getClientId()); response.setFieldName(pushCwUpdateRequest.getFieldName()); response.setParams(pushCwUpdateRequest.getParams()); response.setClassIdPair(pushCwUpdateRequest.getClassIdPair()); From e8a4d5dba14d042990aaeb96ea404cfb67249d6e Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Wed, 26 Aug 2015 06:36:52 -0700 Subject: [PATCH 03/20] Adding ICacheDataStore interface and making RedisDataStore compatible with redis cluster --- pom.xml | 7 + .../sync/access/RedisAccessManager.java | 6 +- .../sync/datastore/ICacheDataStore.java | 170 ++++++++++++ ...ataStore.java => RedisCacheDataStore.java} | 259 +++++++++++++++++- .../datastore/RedisClusterCacheDataStore.java | 136 +++++++++ .../sync/datastore/RedisClusterDataStore.java | 257 ----------------- .../sync/helpers/RedisPostClientHelper.java | 23 +- .../sync/services/SyncAgentDataProvider.java | 54 ++-- .../sync/services/SyncAgentService.java | 36 +-- .../RedisClusterCacheDataStoreTest.java | 142 ++++++++++ 10 files changed, 764 insertions(+), 326 deletions(-) create mode 100644 src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java rename src/main/java/com/percero/agents/sync/datastore/{RedisDataStore.java => RedisCacheDataStore.java} (56%) create mode 100644 src/main/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStore.java delete mode 100644 src/main/java/com/percero/agents/sync/datastore/RedisClusterDataStore.java create mode 100644 src/test/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStoreTest.java diff --git a/pom.xml b/pom.xml index d324003..ccca2fd 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,7 @@ 1.6.1 1.19.0 1.19.0 + 1.9.5 @@ -33,6 +34,12 @@ 4.8.2 test + + org.mockito + mockito-core + ${mockito-core.version} + test + org.codehaus.jackson diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index 14ad62b..09af58a 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -26,7 +26,7 @@ import com.percero.agents.sync.cw.ChangeWatcherReporting; import com.percero.agents.sync.cw.IChangeWatcherHelper; import com.percero.agents.sync.cw.IChangeWatcherHelperFactory; -import com.percero.agents.sync.datastore.RedisDataStore; +import com.percero.agents.sync.datastore.ICacheDataStore; import com.percero.agents.sync.exceptions.ClientException; import com.percero.agents.sync.helpers.RedisPostClientHelper; import com.percero.agents.sync.services.IPushSyncHelper; @@ -75,8 +75,8 @@ public void setPostClientHelper(RedisPostClientHelper value) { //MongoOperations mongoOperations; @Autowired - RedisDataStore redisDataStore; - public void setRedisDataStore(RedisDataStore redisDataStore) { + ICacheDataStore redisDataStore; + public void setRedisDataStore(ICacheDataStore redisDataStore) { this.redisDataStore = redisDataStore; } diff --git a/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java b/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java new file mode 100644 index 0000000..c82acf3 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java @@ -0,0 +1,170 @@ +package com.percero.agents.sync.datastore; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.SetOperations; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.transaction.annotation.Transactional; + +public interface ICacheDataStore { + + public abstract Boolean expire(String key, long timeout, TimeUnit timeUnit); + + public abstract Boolean expire(Collection keys, long timeout, + TimeUnit timeUnit); + + public abstract Boolean expire(String key, long timeout, TimeUnit timeUnit, + Boolean forceNow); + + public abstract Boolean expire(Collection keys, long timeout, + TimeUnit timeUnit, Boolean forceNow); + + @Scheduled(fixedRate = 600000) + // 10 * 60 * 1000 -> Ten Minutes. + public abstract void postExpires(); + + public abstract Object getValue(String key); + + public abstract List getValues(Collection keys); + + public abstract void setValue(String key, Object value); + + // public void setValues( final KeyValuePair[] pairs ) { + public abstract void setValues( + Map keysAndValuesMap); + + @Transactional + public abstract Long addSetValue(String key, Object value); + + @Transactional + public abstract Long lpushListValue(String key, Object value); + + @Transactional + public abstract List listAll(String key); + + @Transactional + public abstract List listRange(String key, Long start, Long end); + + @Transactional + public abstract Object listIndex(String key, Long index); + + @Transactional + public abstract Object listIndex(String key); + + @Transactional + public abstract Object getHashValue(String key, String hashKey); + + @Transactional + public abstract Set getHashKeys(String key); + + @Transactional + public abstract Map getHashEntries(String key); + + @Transactional + public abstract Long getHashSize(String key); + + @Transactional + public abstract void deleteHashKey(String key, Object hashKey); + + @Transactional + public abstract void setHashValue(String key, String hashKey, Object value); + + @Transactional + public abstract void setAllHashValues(String key, + Map hashMap); + + @Transactional + public abstract Long removeSetValue(String key, Object value); + + @Transactional + public abstract Boolean getSetIsEmpty(String key); + + @Transactional + public abstract Long removeSetValueAndGetSize(String key, Object value); + + public abstract void removeSetsValue(Collection keys, + Object value); + + public abstract void removeSetsValue(String keysPrefix, + Collection keys, Object value); + + public abstract Boolean hasKey(String key); + + public abstract Boolean hasHashKey(String key, String hashKey); + + @Transactional + public abstract void swapHashKey(String key, String oldHashKey, + String newHashValue); + + public abstract Boolean renameIfAbsent(String oldKey, String newKey); + + public abstract void rename(String oldKey, String newKey); + + public abstract Long setUnionAndStore(String key, String otherKey, + String destKey); + + public abstract Long setUnionAndStore(String key, + Collection otherKeys, String destKey); + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#removeSetValues(java.lang.String, java.util.Collection) + */ + @Transactional + public abstract void removeSetValues(String key, + Collection values); + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetValue(java.lang.String) + */ + public abstract Set getSetValue(String key); + + @Transactional + public abstract Long replaceSet(String key, + Collection values); + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#swapSetValue(java.lang.String, java.lang.String, java.lang.String) + */ + @Transactional + public abstract void swapSetValue(String key, String oldValue, + String newValue); + + public abstract Boolean getSetIsMember(String key, Object object); + + @Transactional + public abstract Set getSetsContainsMembers( + Collection keys, Object[] membersToCheck); + + public abstract Set getSetIntersect(String key, + Collection otherKeys); + + public abstract Set getSetIntersect(String key, String otherKey); + + public abstract Set getSetUnion(String key, + Collection otherKeys); + + public abstract Set getSetUnion(String key, + String otherKey); + + public abstract void deleteKey(String key); + + public abstract void deleteKeys(Collection keys); + + @Transactional + public abstract Long setSetValue(String key, Object value); + + public abstract SetOperations getSet(String key); + + public abstract RedisTemplate getTemplate(); + + public abstract Collection keys(String pattern); + + @Transactional + public abstract void removeKeysValue(String pattern, Object value); + +} \ No newline at end of file diff --git a/src/main/java/com/percero/agents/sync/datastore/RedisDataStore.java b/src/main/java/com/percero/agents/sync/datastore/RedisCacheDataStore.java similarity index 56% rename from src/main/java/com/percero/agents/sync/datastore/RedisDataStore.java rename to src/main/java/com/percero/agents/sync/datastore/RedisCacheDataStore.java index cfbcb4d..8b28621 100644 --- a/src/main/java/com/percero/agents/sync/datastore/RedisDataStore.java +++ b/src/main/java/com/percero/agents/sync/datastore/RedisCacheDataStore.java @@ -12,32 +12,42 @@ import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.SetOperations; import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import com.percero.agents.sync.access.KeyValuePair; import com.percero.agents.sync.services.PerceroRedisTemplate; import edu.emory.mathcs.backport.java.util.Collections; -@Component -public class RedisDataStore { +public class RedisCacheDataStore implements ICacheDataStore { - private static Logger log = Logger.getLogger(RedisDataStore.class); + private static Logger log = Logger.getLogger(RedisCacheDataStore.class); @Autowired - private PerceroRedisTemplate template; + protected PerceroRedisTemplate template; + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.lang.String, long, java.util.concurrent.TimeUnit) + */ + @Override public Boolean expire( final String key, final long timeout, final TimeUnit timeUnit ) { return expire(key, timeout, timeUnit, false); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.util.Collection, long, java.util.concurrent.TimeUnit) + */ + @Override public Boolean expire( final Collection keys, final long timeout, final TimeUnit timeUnit ) { return expire(keys, timeout, timeUnit, false); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.lang.String, long, java.util.concurrent.TimeUnit, java.lang.Boolean) + */ + @Override public Boolean expire( final String key, final long timeout, final TimeUnit timeUnit, Boolean forceNow ) { if (forceNow) { return template.expire(key, timeout, timeUnit); @@ -48,6 +58,10 @@ public Boolean expire( final String key, final long timeout, final TimeUnit time } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.util.Collection, long, java.util.concurrent.TimeUnit, java.lang.Boolean) + */ + @Override public Boolean expire( final Collection keys, final long timeout, final TimeUnit timeUnit, Boolean forceNow ) { if (forceNow) { Iterator itrKeys = keys.iterator(); @@ -71,6 +85,10 @@ public Boolean expire( final Collection keys, final long timeout, final @SuppressWarnings("unchecked") private Map expiresToBeWritten = Collections.synchronizedMap(new HashMap()); + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#postExpires() + */ + @Override @Scheduled(fixedRate=600000) // 10 * 60 * 1000 -> Ten Minutes. public void postExpires() { log.info("Posting " + expiresToBeWritten.size() + " expire" + (expiresToBeWritten.size() == 1 ? "" : "s")); @@ -112,19 +130,35 @@ public PendingExpire(String key, long timeout, TimeUnit timeUnit) { } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getValue(java.lang.String) + */ + @Override public Object getValue( final String key ) { return template.opsForValue().get( key ); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getValues(java.util.Collection) + */ + @Override public List getValues( final Collection keys ) { return template.opsForValue().multiGet(keys); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setValue(java.lang.String, java.lang.Object) + */ + @Override public void setValue( final String key, final Object value ) { template.opsForValue().set( key, value ); } // public void setValues( final KeyValuePair[] pairs ) { + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setValues(java.util.Map) + */ + @Override public void setValues( final Map keysAndValuesMap ) { template.opsForValue().multiSet(keysAndValuesMap); // if (pairs != null) { @@ -134,83 +168,146 @@ public void setValues( final Map keysAndValuesMap ) { // } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#addSetValue(java.lang.String, java.lang.Object) + */ + @Override @Transactional public Long addSetValue( final String key, final Object value ) { return template.opsForSet().add(key, value);// ? Long.valueOf(1) : Long.valueOf(0); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#lpushListValue(java.lang.String, java.lang.Object) + */ + @Override @Transactional public Long lpushListValue( final String key, final Object value ) { return template.opsForList().leftPush(key, value); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listAll(java.lang.String) + */ + @Override @Transactional public List listAll( final String key) { return listRange(key, Long.valueOf(0), Long.valueOf(-1)); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listRange(java.lang.String, java.lang.Long, java.lang.Long) + */ + @Override @Transactional public List listRange( final String key, final Long start, final Long end ) { return template.opsForList().range(key, start, end); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listIndex(java.lang.String, java.lang.Long) + */ + @Override @Transactional public Object listIndex( final String key, final Long index ) { return template.opsForList().index(key, index); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listIndex(java.lang.String) + */ + @Override @Transactional public Object listIndex( final String key ) { return template.opsForList().index(key, Long.valueOf(0)); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashValue(java.lang.String, java.lang.String) + */ + @Override @Transactional public Object getHashValue( final String key, final String hashKey ) { return template.opsForHash().get(key, hashKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashKeys(java.lang.String) + */ + @Override @Transactional public Set getHashKeys( final String key ) { return template.opsForHash().keys(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashEntries(java.lang.String) + */ + @Override @Transactional public Map getHashEntries( final String key ) { return template.opsForHash().entries(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashSize(java.lang.String) + */ + @Override @Transactional public Long getHashSize( final String key ) { return template.opsForHash().size(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#deleteHashKey(java.lang.String, java.lang.Object) + */ + @Override @Transactional public void deleteHashKey( final String key, final Object hashKey ) { template.opsForHash().delete(key, hashKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setHashValue(java.lang.String, java.lang.String, java.lang.Object) + */ + @Override @Transactional public void setHashValue( final String key, final String hashKey, final Object value ) { template.opsForHash().put(key, hashKey, value); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setAllHashValues(java.lang.String, java.util.Map) + */ + @Override @Transactional public void setAllHashValues( final String key, final Map hashMap ) { template.opsForHash().putAll(key, hashMap); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetValue(java.lang.String, java.lang.Object) + */ + @Override @Transactional public Long removeSetValue( final String key, final Object value ) { - Long result = template.opsForSet().remove(key, value);// ? Long.valueOf(1) : Long.valueOf(0); - return result; + return template.opsForSet().remove(key, value);// ? Long.valueOf(1) : Long.valueOf(0); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIsEmpty(java.lang.String) + */ + @Override @Transactional public Boolean getSetIsEmpty( final String key ) { Long result = template.opsForSet().size(key);// ? Long.valueOf(1) : Long.valueOf(0); return (result <= 0); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetValueAndGetSize(java.lang.String, java.lang.Object) + */ + @Override @Transactional public Long removeSetValueAndGetSize( final String key, final Object value ) { SetOperations setOps = template.opsForSet(); @@ -218,6 +315,10 @@ public Long removeSetValueAndGetSize( final String key, final Object value ) { return setOps.size(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetsValue(java.util.Collection, java.lang.Object) + */ + @Override public void removeSetsValue( final Collection keys, final Object value ) { SetOperations setOps = template.opsForSet(); Iterator itrKeys = keys.iterator(); @@ -231,6 +332,10 @@ public void removeSetsValue( final Collection keys, final Obje } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetsValue(java.lang.String, java.util.Collection, java.lang.Object) + */ + @Override public void removeSetsValue( final String keysPrefix, final Collection keys, final Object value ) { SetOperations setOps = template.opsForSet(); Iterator itrKeys = keys.iterator(); @@ -244,7 +349,7 @@ public void removeSetsValue( final String keysPrefix, final Collection keys(String pattern) { // Set result = template.keys(pattern); // log.info("Keys: " + ++keysCount); @@ -252,16 +357,28 @@ public void removeSetsValue( final String keysPrefix, final Collection hashOps = template.opsForHash(); @@ -271,22 +388,45 @@ public void swapHashKey( final String key, final String oldHashKey, final String } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#renameIfAbsent(java.lang.String, java.lang.String) + */ + @Override public Boolean renameIfAbsent(String oldKey, String newKey) { return template.renameIfAbsent(oldKey, newKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#rename(java.lang.String, java.lang.String) + */ + @Override public void rename(String oldKey, String newKey) { template.rename(oldKey, newKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setUnionAndStore(java.lang.String, java.lang.String, java.lang.String) + */ + @Override public Long setUnionAndStore(String key, String otherKey, String destKey) { return template.opsForSet().unionAndStore(key, otherKey, destKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setUnionAndStore(java.lang.String, java.util.Collection, java.lang.String) + */ + @Override public Long setUnionAndStore(String key, Collection otherKeys, String destKey) { return template.opsForSet().unionAndStore(key, otherKeys, destKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#removeSetValues(java.lang.String, java.util.Collection) + */ + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetValues(java.lang.String, java.util.Collection) + */ + @Override @Transactional public void removeSetValues( final String key, final Collection values ) { SetOperations setOps = template.opsForSet(); @@ -301,10 +441,21 @@ public void removeSetValues( final String key, final Collection getSetValue( final String key ) { return template.opsForSet().members(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#replaceSet(java.lang.String, java.util.Collection) + */ + @Override @Transactional public Long replaceSet( final String key, Collection values ) { template.delete(key); @@ -316,6 +467,13 @@ public Long replaceSet( final String key, Collection values ) } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#swapSetValue(java.lang.String, java.lang.String, java.lang.String) + */ + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#swapSetValue(java.lang.String, java.lang.String, java.lang.String) + */ + @Override @Transactional public void swapSetValue( final String key, final String oldValue, final String newValue ) { SetOperations setOps = template.opsForSet(); @@ -325,10 +483,18 @@ public void swapSetValue( final String key, final String oldValue, final String } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIsMember(java.lang.String, java.lang.Object) + */ + @Override public Boolean getSetIsMember( final String key, final Object object ) { return template.opsForSet().isMember(key, object); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetsContainsMembers(java.util.Collection, java.lang.Object[]) + */ + @Override @Transactional public Set getSetsContainsMembers( final Collection keys, final Object[] membersToCheck ) { SetOperations setOps = template.opsForSet(); @@ -345,30 +511,105 @@ public Set getSetsContainsMembers( final Collection ke return intersectingMembers; } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIntersect(java.lang.String, java.util.Collection) + */ + @Override public Set getSetIntersect( final String key, Collection otherKeys ) { return template.opsForSet().intersect(key, otherKeys); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIntersect(java.lang.String, java.lang.String) + */ + @Override public Set getSetIntersect( final String key, String otherKey ) { return template.opsForSet().intersect(key, otherKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetUnion(java.lang.String, java.util.Collection) + */ + @Override public Set getSetUnion( final String key, final Collection otherKeys ) { return template.opsForSet().union(key, otherKeys); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetUnion(java.lang.String, java.lang.String) + */ + @Override public Set getSetUnion( final String key, final String otherKey ) { return template.opsForSet().union(key, otherKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#deleteKey(java.lang.String) + */ + @Override public void deleteKey( final String key ) { template.delete(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#deleteKeys(java.util.Collection) + */ + @Override public void deleteKeys( final Collection keys ) { if (keys != null && !keys.isEmpty()) { template.delete(keys); } } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setSetValue(java.lang.String, java.lang.Object) + */ + @Override + @Transactional + public Long setSetValue(String key, Object value) { + return template.opsForSet().add(key, value);// ? Long.valueOf(1) : Long.valueOf(0); + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSet(java.lang.String) + */ + @Override + public SetOperations getSet(String key) { + return template.opsForSet(); + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getTemplate() + */ + @Override + public RedisTemplate getTemplate() { + return template; + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#keys(java.lang.String) + */ + @Override + public Collection keys(String pattern) { + return template.keys(pattern); + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeKeysValue(java.lang.String, java.lang.Object) + */ + @Override + @Transactional + public void removeKeysValue(String pattern, Object value) { + Set keys = template.keys(pattern); + Iterator itrKeys = keys.iterator(); + + while(itrKeys.hasNext()) { + try { + template.opsForSet().remove(itrKeys.next(), value); + } catch(Exception e) { + log.error("Error removing KeysValue", e); + } + } + } } diff --git a/src/main/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStore.java b/src/main/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStore.java new file mode 100644 index 0000000..a357f8c --- /dev/null +++ b/src/main/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStore.java @@ -0,0 +1,136 @@ +package com.percero.agents.sync.datastore; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.springframework.data.redis.core.SetOperations; +import org.springframework.stereotype.Component; + +@Component +public class RedisClusterCacheDataStore extends RedisCacheDataStore /*implements IRedisClusterCacheDataStore*/ { + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#setUnionAndStore(java.lang.String, java.lang.String, java.lang.String) + */ + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisClusterCacheDataStore#setUnionAndStore(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public Long setUnionAndStore(String key, String otherKey, String destKey) { + SetOperations setOps = template.opsForSet(); + Set existingSet = setOps.members(key); + existingSet.addAll(setOps.members(otherKey)); + + Iterator itr = existingSet.iterator(); + while(itr.hasNext()) { + setOps.add(destKey, itr.next()); + } + + return setOps.size(destKey); + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#setUnionAndStore(java.lang.String, java.util.Collection, java.lang.String) + */ + @Override + public Long setUnionAndStore(String key, Collection otherKeys, String destKey) { + SetOperations setOps = template.opsForSet(); + Set existingSet = setOps.members(key); + + Iterator itrKeys = otherKeys.iterator(); + while(itrKeys.hasNext()) { + String nextKey = itrKeys.next(); + + existingSet.addAll(setOps.members(nextKey)); + + Iterator itr = existingSet.iterator(); + while(itr.hasNext()) { + setOps.add(destKey, itr.next()); + } + } + + return setOps.size(destKey); + } + + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetIntersect(java.lang.String, java.util.Collection) + */ + @Override + public Set getSetIntersect( final String key, Collection otherKeys ) { + SetOperations setOps = template.opsForSet(); + + Set result = setOps.members(key); + + Iterator itrKeys = otherKeys.iterator(); + + while(itrKeys.hasNext()) { + String nextKey = itrKeys.next(); + Set otherSet = setOps.members(nextKey); + + Iterator itr = result.iterator(); + + while(itr.hasNext()) { + Object nextObject = itr.next(); + if (!otherSet.contains(nextObject)) { + itr.remove(); + } + } + } + + return result; + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetIntersect(java.lang.String, java.lang.String) + */ + @Override + public Set getSetIntersect( final String key, String otherKey ) { + SetOperations setOps = template.opsForSet(); + + Set theSet = setOps.members(key); + Set otherSet = setOps.members(otherKey); + Set result = new HashSet(); + + Iterator itr = theSet.iterator(); + + while(itr.hasNext()) { + Object nextObject = itr.next(); + if (otherSet.contains(nextObject)) { + result.add(nextObject); + } + } + + return result; + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetUnion(java.lang.String, java.util.Collection) + */ + @Override + public Set getSetUnion( final String key, final Collection otherKeys ) { + SetOperations setOps = template.opsForSet(); + + Set theSet = setOps.members(key); + Iterator itr = otherKeys.iterator(); + while(itr.hasNext()) { + theSet.addAll(setOps.members(itr.next())); + } + return theSet; + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetUnion(java.lang.String, java.lang.String) + */ + @Override + public Set getSetUnion( final String key, final String otherKey ) { + SetOperations setOps = template.opsForSet(); + + Set theSet = setOps.members(key); + theSet.addAll(setOps.members(otherKey)); + return theSet; + } + +} diff --git a/src/main/java/com/percero/agents/sync/datastore/RedisClusterDataStore.java b/src/main/java/com/percero/agents/sync/datastore/RedisClusterDataStore.java deleted file mode 100644 index f61e85a..0000000 --- a/src/main/java/com/percero/agents/sync/datastore/RedisClusterDataStore.java +++ /dev/null @@ -1,257 +0,0 @@ -package com.percero.agents.sync.datastore; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.apache.log4j.Logger; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.SetOperations; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -import com.percero.agents.sync.services.PerceroRedisTemplate; - -@Component -public class RedisClusterDataStore { - - private static Logger log = Logger.getLogger(RedisClusterDataStore.class); - - @Autowired - private PerceroRedisTemplate template; - - public Boolean expire( final String key, final long timeout, final TimeUnit timeUnit ) { - return template.expire(key, timeout, timeUnit); - } - - public Object getValue( final String key ) { - return template.opsForValue().get( key ); - } - - public void setValue( final String key, final Object value ) { - template.opsForValue().set( key, value ); - } - - @Transactional - public Long setSetValue( final String key, final Object value ) { - return template.opsForSet().add(key, value);// ? Long.valueOf(1) : Long.valueOf(0); - } - - @Transactional - public Long lpushListValue( final String key, final Object value ) { - return template.opsForList().leftPush(key, value); - } - - @Transactional - public List listAll( final String key) { - return listRange(key, Long.valueOf(0), Long.valueOf(-1)); - } - - @Transactional - public List listRange( final String key, final Long start, final Long end ) { - return template.opsForList().range(key, start, end); - } - - @Transactional - public Object listIndex( final String key, final Long index ) { - return template.opsForList().index(key, index); - } - - @Transactional - public Object listIndex( final String key ) { - return template.opsForList().index(key, Long.valueOf(0)); - } - - @Transactional - public void setHashValue( final String key, final String hashKey, final Object value ) { - template.opsForHash().put(key, hashKey, value); - } - - @Transactional - public Long removeSetValue( final String key, final Object value ) { - return template.opsForSet().remove(key, value);// ? Long.valueOf(1) : Long.valueOf(0); - } - - public void removeSetsValue( final Collection keys, final Object value ) { - SetOperations setOps = template.opsForSet(); - Iterator itrKeys = keys.iterator(); - while(itrKeys.hasNext()) { - String nextKey = itrKeys.next(); - setOps.remove(nextKey, value); - } - } - - public SetOperations getSet( final String key ) { - return template.opsForSet(); - } - - public RedisTemplate getTemplate() { - return template; - } - - public Collection keys(String pattern) { - return template.keys(pattern); - } - - public Boolean renameIfAbsent(String oldKey, String newKey) { - return template.renameIfAbsent(oldKey, newKey); - } - - public void rename(String oldKey, String newKey) { - template.rename(oldKey, newKey); - } - - public Long setUnionAndStore(String key, String otherKey, String destKey) { - SetOperations setOps = template.opsForSet(); - Set existingSet = setOps.members(key); - existingSet.addAll(setOps.members(otherKey)); - - Iterator itr = existingSet.iterator(); - while(itr.hasNext()) { - setOps.add(destKey, itr.next()); - } - - return setOps.size(destKey); - } - - public Long setUnionAndStore(String key, Collection otherKeys, String destKey) { - SetOperations setOps = template.opsForSet(); - Set existingSet = setOps.members(key); - - Iterator itrKeys = otherKeys.iterator(); - while(itrKeys.hasNext()) { - String nextKey = itrKeys.next(); - - existingSet.addAll(setOps.members(nextKey)); - - Iterator itr = existingSet.iterator(); - while(itr.hasNext()) { - setOps.add(destKey, itr.next()); - } - } - - return setOps.size(destKey); - } - - @Transactional - public void removeKeysValue( final String pattern, final Object value ) { - Set keys = template.keys(pattern); - Iterator itrKeys = keys.iterator(); - - while(itrKeys.hasNext()) { - try { - template.opsForSet().remove(itrKeys.next(), value); - } catch(Exception e) { - log.error("Error removing KeysValue", e); - } - } - } - - @Transactional - public void removeSetValues( final String key, final Collection values ) { - SetOperations setOps = template.opsForSet(); - - Iterator itrValues = values.iterator(); - while(itrValues.hasNext()) { - try { - setOps.remove(key, itrValues.next()); - } catch(Exception e) { - log.error("Unable to remove Set Value", e); - } - } - } - - public Set getSetValue( final String key ) { - template.opsForSet().members(key); - return template.opsForSet().members(key); - } - - @Transactional - public void swapSetValue( final String key, final String oldValue, final String newValue ) { - SetOperations setOps = template.opsForSet(); - if (setOps.isMember(key, oldValue)) { - setOps.remove(key, oldValue); - setOps.add(key, newValue); - } - } - - public Boolean getSetIsMember( final String key, final Object object ) { - - return template.opsForSet().isMember(key, object); - } - - public Set getSetIntersect( final String key, Collection otherKeys ) { - SetOperations setOps = template.opsForSet(); - - Set result = setOps.members(key); - - Iterator itrKeys = otherKeys.iterator(); - - while(itrKeys.hasNext()) { - String nextKey = itrKeys.next(); - Set otherSet = setOps.members(nextKey); - - Iterator itr = result.iterator(); - - while(itr.hasNext()) { - Object nextObject = itr.next(); - if (!otherSet.contains(nextObject)) { - itr.remove(); - } - } - } - - return result; - } - - public Set getSetIntersect( final String key, String otherKey ) { - SetOperations setOps = template.opsForSet(); - - Set theSet = setOps.members(key); - Set otherSet = setOps.members(otherKey); - Set result = new HashSet(); - - Iterator itr = theSet.iterator(); - - while(itr.hasNext()) { - Object nextObject = itr.next(); - if (otherSet.contains(nextObject)) { - result.add(nextObject); - } - } - - return result; - } - - public Set getSetUnion( final String key, final Collection otherKeys ) { - SetOperations setOps = template.opsForSet(); - - Set theSet = setOps.members(key); - Iterator itr = otherKeys.iterator(); - while(itr.hasNext()) { - theSet.addAll(setOps.members(itr.next())); - } - return theSet; - } - - public Set getSetUnion( final String key, final String otherKey ) { - SetOperations setOps = template.opsForSet(); - - Set theSet = setOps.members(key); - theSet.addAll(setOps.members(otherKey)); - return theSet; - } - - public void deleteKey( final String key ) { - template.delete(key); - } - - public void deleteKeys( final Collection keys ) { - if (keys.size() > 0) - template.delete(keys); - } -} diff --git a/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java b/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java index 2f3934b..dca6fe0 100644 --- a/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java @@ -2,7 +2,6 @@ import java.util.Collection; import java.util.Iterator; -import java.util.Set; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; @@ -12,7 +11,7 @@ import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.access.RedisKeyUtils; -import com.percero.agents.sync.datastore.RedisDataStore; +import com.percero.agents.sync.datastore.ICacheDataStore; @Component public class RedisPostClientHelper { @@ -20,7 +19,7 @@ public class RedisPostClientHelper { private static final Logger log = Logger.getLogger(RedisPostClientHelper.class); @Autowired - private RedisDataStore redisDataStore; + private ICacheDataStore cacheDataStore; @Autowired IAccessManager accessManager; @@ -34,11 +33,11 @@ public void setUserDeviceTimeout(Long value) { @Transactional public void postClient(String clientId) throws Exception { // Get the client's userId. - String userId = (String) redisDataStore.getValue(RedisKeyUtils.client(clientId)); + String userId = (String) cacheDataStore.getValue(RedisKeyUtils.client(clientId)); if (userId != null && userId.length() > 0) { // Timeout Client's User ID. - redisDataStore.expire(RedisKeyUtils.client(clientId), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(RedisKeyUtils.client(clientId), userDeviceTimeout, TimeUnit.SECONDS); // Remove from NonPersistent Clients //redisDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); @@ -47,13 +46,13 @@ public void postClient(String clientId) throws Exception { //redisDataStore.removeSetValue(RedisKeyUtils.clientsPersistent(), clientId); // Timeout Client User - redisDataStore.expire(RedisKeyUtils.clientUser(userId), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(RedisKeyUtils.clientUser(userId), userDeviceTimeout, TimeUnit.SECONDS); // Timeout UpdateJournals for this Client. - redisDataStore.expire(RedisKeyUtils.updateJournal(clientId), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(RedisKeyUtils.updateJournal(clientId), userDeviceTimeout, TimeUnit.SECONDS); // Timeout DeleteJournals for this Client. - redisDataStore.expire(RedisKeyUtils.deleteJournal(clientId), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(RedisKeyUtils.deleteJournal(clientId), userDeviceTimeout, TimeUnit.SECONDS); // // Timeout TransactionJournals for this Client. // Collection transJournalKeys = redisDataStore.keys(RedisKeyUtils.transactionJournal(clientId, "*")); @@ -65,13 +64,13 @@ public void postClient(String clientId) throws Exception { // Timeout Client's UserDevice. // Collection userDeviceKeys = redisDataStore.keys(RedisKeyUtils.userDevice(userId, "*")); // TODO: This expire no longer works!!! - Collection userDeviceKeys = redisDataStore.getHashKeys(RedisKeyUtils.userDeviceHash(userId)); + Collection userDeviceKeys = cacheDataStore.getHashKeys(RedisKeyUtils.userDeviceHash(userId)); Iterator itrUserDevices = userDeviceKeys.iterator(); while (itrUserDevices.hasNext()) { String nextKey = (String) itrUserDevices.next(); - if (clientId.equals(redisDataStore.getValue(nextKey))) { - redisDataStore.expire(RedisKeyUtils.deviceHash(nextKey), userDeviceTimeout, TimeUnit.SECONDS); - redisDataStore.expire(nextKey, userDeviceTimeout, TimeUnit.SECONDS); + if (clientId.equals(cacheDataStore.getValue(nextKey))) { + cacheDataStore.expire(RedisKeyUtils.deviceHash(nextKey), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(nextKey, userDeviceTimeout, TimeUnit.SECONDS); } } } diff --git a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java b/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java index d933039..e74656b 100644 --- a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java @@ -37,7 +37,7 @@ import org.springframework.util.StringUtils; import com.percero.agents.sync.access.RedisKeyUtils; -import com.percero.agents.sync.datastore.RedisDataStore; +import com.percero.agents.sync.datastore.ICacheDataStore; import com.percero.agents.sync.exceptions.SyncDataException; import com.percero.agents.sync.exceptions.SyncException; import com.percero.agents.sync.hibernate.AssociationExample; @@ -77,7 +77,7 @@ public String getName() { } @Autowired - RedisDataStore redisDataStore; + ICacheDataStore cacheDataStore; @Autowired Long cacheTimeout = Long.valueOf(60 * 60 * 24 * 14); // Two weeks @@ -463,7 +463,7 @@ public IPerceroObject systemGetById(ClassIDPair classIdPair) { key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); if (cacheTimeout > 0) - redisDataStore.setValue(key, ((BaseDataObject)result).toJson()); + cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); } else { // Not necessarily a problem but could be helpful when debugging. @@ -476,7 +476,7 @@ public IPerceroObject systemGetById(ClassIDPair classIdPair) { // (Re)Set the expiration. if (cacheTimeout > 0 && key != null) { - redisDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); } return result; @@ -514,7 +514,7 @@ public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); if (cacheTimeout > 0) - redisDataStore.setValue(key, ((BaseDataObject)result).toJson()); + cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); } else { log.warn("Unable to retrieve object from database: " + classIdPair.toString()); @@ -526,7 +526,7 @@ public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, // (Re)Set the expiration. if (cacheTimeout > 0 && key != null) { - redisDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); } return result; @@ -555,7 +555,7 @@ private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Ex MappedClass mc = mcm.getMappedClassByClassName(classIdPair.getClassName()); String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); - String jsonObjectString = (String) redisDataStore.getValue(key); + String jsonObjectString = (String) cacheDataStore.getValue(key); if (jsonObjectString != null) { if (IJsonObject.class.isAssignableFrom(theClass)) { IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); @@ -572,7 +572,7 @@ private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Ex while (itrChildMappedClasses.hasNext()) { MappedClass nextChildMc = itrChildMappedClasses.next(); key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); - jsonObjectString = (String) redisDataStore.getValue(key); + jsonObjectString = (String) cacheDataStore.getValue(key); if (jsonObjectString != null) { result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); return result; @@ -614,7 +614,7 @@ private Map retrieveFromRedisCache(ClassIDPairs classIdP } // String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); - List jsonObjectStrings = redisDataStore.getValues(keys); + List jsonObjectStrings = cacheDataStore.getValues(keys); Iterator itrJsonObjectStrings = jsonObjectStrings.iterator(); while (itrJsonObjectStrings.hasNext()) { String jsonObjectString = (String) itrJsonObjectStrings.next(); @@ -646,7 +646,7 @@ private Map retrieveFromRedisCache(ClassIDPairs classIdP } if (pleaseSetTimeout) { - redisDataStore.expire(keys, cacheTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(keys, cacheTimeout, TimeUnit.SECONDS); } } @@ -873,9 +873,9 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) } // Store the objects in redis. - redisDataStore.setValues(mapJsonObjectStrings); + cacheDataStore.setValues(mapJsonObjectStrings); // (Re)Set the expiration. - redisDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); } if (result == null) { @@ -1080,8 +1080,8 @@ public IPerceroObject systemCreateObject(IPerceroObject perceroObject) if (cacheTimeout > 0) { String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); if (cacheTimeout > 0) { - redisDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); - redisDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); } Set keysToDelete = new HashSet(); @@ -1130,7 +1130,7 @@ else if (fieldObject instanceof Collection) { } if (!keysToDelete.isEmpty()) { - redisDataStore.deleteKeys(keysToDelete); + cacheDataStore.deleteKeys(keysToDelete); // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); } @@ -1284,8 +1284,8 @@ public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map 0) { // TODO: Also need to update the caches of anything object that is related to this object. String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); - if (redisDataStore.hasKey(key)) { - redisDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + if (cacheDataStore.hasKey(key)) { + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); } // Iterate through each changed object and reset the cache for that object. @@ -1311,7 +1311,7 @@ public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map getHistory(String aClassName, String anId, String clientId) if (hasReadAccess) { // Get the Historical Objects. - return redisDataStore.listAll(RedisKeyUtils.historicalObject(aClassName, anId)); + return cacheDataStore.listAll(RedisKeyUtils.historicalObject(aClassName, anId)); } return null; @@ -645,7 +645,7 @@ public ServerResponse putObject(IPerceroObject perceroObject, String transaction // Get the most recent ObjectModJournal, only if the UpdateDate is set. if (updateDate != null) { try { - objectModJournal = (ObjectModJournal) redisDataStore.listIndex(RedisKeyUtils.objectModJournal(perceroObject.getClass().getName(), perceroObject.getID())); + objectModJournal = (ObjectModJournal) cacheDataStore.listIndex(RedisKeyUtils.objectModJournal(perceroObject.getClass().getName(), perceroObject.getID())); } catch(Exception e) { log.warn("Unable to retrieve most recent objectModJournal", e); } @@ -692,7 +692,7 @@ public ServerResponse putObject(IPerceroObject perceroObject, String transaction newModJournal.setClassID(result.getID()); newModJournal.setClassName(result.getClass().getName()); - redisDataStore.lpushListValue(RedisKeyUtils.objectModJournal(perceroObject.getClass().getCanonicalName(), perceroObject.getID()), newModJournal); + cacheDataStore.lpushListValue(RedisKeyUtils.objectModJournal(perceroObject.getClass().getCanonicalName(), perceroObject.getID()), newModJournal); // Also store historical record, if necessary. // Get the Current object if this is a BaseHistoryObject. @@ -707,7 +707,7 @@ public ServerResponse putObject(IPerceroObject perceroObject, String transaction historyObject.setObjectChangerId(userId); historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); - redisDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); } if (taskExecutor != null && false) { @@ -755,7 +755,7 @@ public boolean systemPutObject(IPerceroObject perceroObject, String transactionI try { // Get the most recent ObjectModJournal. try { - objectModJournal = (ObjectModJournal) redisDataStore.listIndex(RedisKeyUtils.objectModJournal(perceroObject.getClass().getName(), perceroObject.getID())); + objectModJournal = (ObjectModJournal) cacheDataStore.listIndex(RedisKeyUtils.objectModJournal(perceroObject.getClass().getName(), perceroObject.getID())); } catch(Exception e) { log.warn("Unable to retrieve most recent objectModJournal", e); } @@ -795,7 +795,7 @@ public boolean systemPutObject(IPerceroObject perceroObject, String transactionI newModJournal.setClassName(result.getClass().getName()); newModJournal.setDateModified(updateDate); - redisDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); + cacheDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); // Also store historical record, if necessary. // Get the Current object if this is a BaseHistoryObject. @@ -810,7 +810,7 @@ public boolean systemPutObject(IPerceroObject perceroObject, String transactionI historyObject.setObjectChangerId(userId); historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); - redisDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); //syncSession.save(historyObject); } @@ -873,7 +873,7 @@ public ServerResponse createObject(IPerceroObject perceroObject, String clientId newModJournal.setClassName(result.getClass().getName()); try { - redisDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); + cacheDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); } catch(Exception e) { log.error("Unable to save mod journal to redis cache", e); } @@ -892,7 +892,7 @@ public ServerResponse createObject(IPerceroObject perceroObject, String clientId historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); try { - redisDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); } catch(Exception e) { log.error("Unable to save history object to redis cache", e); } @@ -954,7 +954,7 @@ public T systemCreateObject(IPerceroObject perceroObj newModJournal.setClassName(result.getClass().getName()); try { - redisDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); + cacheDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); } catch(Exception e) { log.error("Unable to save mod journal to redis cache", e); } @@ -973,7 +973,7 @@ public T systemCreateObject(IPerceroObject perceroObj historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); try { - redisDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); } catch(Exception e) { log.error("Unable to save history object to redis cache", e); } @@ -1211,7 +1211,7 @@ else if (nextToManyField instanceof MappedFieldList) { historyObject.setObjectChangerId(userId); historyObject.setObjectData(safeObjectMapper.writeValueAsString(perceroObject)); - redisDataStore.lpushListValue(RedisKeyUtils.historicalObject(perceroObject.getClass().getCanonicalName(), perceroObject.getID()), historyObject); + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(perceroObject.getClass().getCanonicalName(), perceroObject.getID()), historyObject); } catch(Exception e) { log.warn("Unable to save HistoricalObject in deleteObject", e); } diff --git a/src/test/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStoreTest.java b/src/test/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStoreTest.java new file mode 100644 index 0000000..8e9834a --- /dev/null +++ b/src/test/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStoreTest.java @@ -0,0 +1,142 @@ +package com.percero.agents.sync.datastore; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.ListOperations; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.SetOperations; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.data.redis.core.ZSetOperations; + +import com.percero.agents.sync.services.PerceroRedisTemplate; + +@RunWith(MockitoJUnitRunner.class) +public class RedisClusterCacheDataStoreTest { + + @Mock + private PerceroRedisTemplate template; + + @InjectMocks + private RedisClusterCacheDataStore redisCacheDataStore; + + @Mock + private SetOperations setOperations; + + @Mock + private ListOperations listOperations; + + @Mock + private HashOperations hashOperations; + + @Mock + private ValueOperations valueOperations; + + @Mock + private ZSetOperations zsetOperations; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { +// redisCacheDataStore = new RedisCacheDataStore(); + + Mockito.when(template.opsForSet()).thenReturn(setOperations); + Mockito.when(template.opsForList()).thenReturn(listOperations); + Mockito.when(template.opsForHash()).thenReturn(hashOperations); + Mockito.when(template.opsForValue()).thenReturn(valueOperations); + Mockito.when(template.opsForZSet()).thenReturn(zsetOperations); + } + + @SuppressWarnings("unchecked") + @After + public void tearDown() throws Exception { + // Confirm that no non-cluster safe operations have been performed. + + // Sets + Mockito.verify(setOperations, Mockito.never()).union(Mockito.anyString(), Mockito.anyCollection()); + Mockito.verify(setOperations, Mockito.never()).union(Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).unionAndStore(Mockito.anyString(), Mockito.anyCollection(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).unionAndStore(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).difference(Mockito.anyString(), Mockito.anyCollection()); + Mockito.verify(setOperations, Mockito.never()).difference(Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).differenceAndStore(Mockito.anyString(), Mockito.anyCollection(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).differenceAndStore(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).intersect(Mockito.anyString(), Mockito.anyCollection()); + Mockito.verify(setOperations, Mockito.never()).intersect(Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).intersectAndStore(Mockito.anyString(), Mockito.anyCollection(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).intersectAndStore(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).move(Mockito.anyString(), Mockito.anyObject(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).scan(Mockito.anyString(), Mockito.any(ScanOptions.class)); + + // ZSets + Mockito.verify(zsetOperations, Mockito.never()).unionAndStore(Mockito.anyString(), Mockito.anyCollection(), Mockito.anyString()); + Mockito.verify(zsetOperations, Mockito.never()).unionAndStore(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + Mockito.verify(zsetOperations, Mockito.never()).intersectAndStore(Mockito.anyString(), Mockito.anyCollection(), Mockito.anyString()); + Mockito.verify(zsetOperations, Mockito.never()).intersectAndStore(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + Mockito.verify(zsetOperations, Mockito.never()).scan(Mockito.anyString(), Mockito.any(ScanOptions.class)); + + // Hashes + Mockito.verify(hashOperations, Mockito.never()).scan(Mockito.anyString(), Mockito.any(ScanOptions.class)); + + // Value + Mockito.verify(valueOperations, Mockito.never()).multiGet(Mockito.anyCollection()); + + } + + @Test + public void testExpire() { + String key = "KEY"; + long timeout = 1000; + TimeUnit timeUnit = TimeUnit.MILLISECONDS; + + redisCacheDataStore.expire(key, timeout, timeUnit); + Mockito.verify(template, Mockito.never()).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + redisCacheDataStore.expire(key, timeout, timeUnit, false); + Mockito.verify(template, Mockito.never()).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + Collection keys = new ArrayList(); + keys.add("KEY_1"); + keys.add("KEY_2"); + + redisCacheDataStore.expire(keys, timeout, timeUnit); + Mockito.verify(template, Mockito.never()).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + redisCacheDataStore.expire(keys, timeout, timeUnit, false); + Mockito.verify(template, Mockito.never()).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + + redisCacheDataStore.expire(key, timeout, timeUnit, true); + Mockito.verify(template, Mockito.times(1)).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + // Test exit from expire loop. + Mockito.when(template.expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class))).thenReturn(false); + redisCacheDataStore.expire(keys, timeout, timeUnit, true); + Mockito.verify(template, Mockito.times(2)).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + // Test complete expire loop + Mockito.when(template.expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class))).thenReturn(true); + redisCacheDataStore.expire(keys, timeout, timeUnit, true); + Mockito.verify(template, Mockito.times(4)).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + } + +} From c7aeda8c56adf6d9c065827db71f3497bbb677e2 Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Wed, 26 Aug 2015 06:45:21 -0700 Subject: [PATCH 04/20] Renaming ICacheDataStore --- .../sync/access/RedisAccessManager.java | 280 +++++++++--------- 1 file changed, 140 insertions(+), 140 deletions(-) diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index 09af58a..19f5706 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -75,9 +75,9 @@ public void setPostClientHelper(RedisPostClientHelper value) { //MongoOperations mongoOperations; @Autowired - ICacheDataStore redisDataStore; - public void setRedisDataStore(ICacheDataStore redisDataStore) { - this.redisDataStore = redisDataStore; + ICacheDataStore cacheDataStore; + public void setCacheDataStore(ICacheDataStore cacheDataStore) { + this.cacheDataStore = cacheDataStore; } @Autowired @@ -105,48 +105,48 @@ public void setPushSyncHelper(IPushSyncHelper pushSyncHelper) { public void createClient(String clientId, String userId, String deviceType, String deviceId) throws Exception { String clientUserKey = RedisKeyUtils.clientUser(userId); - redisDataStore.addSetValue(clientUserKey, clientId); + cacheDataStore.addSetValue(clientUserKey, clientId); if (StringUtils.hasText(deviceId)) { String userDeviceKey = RedisKeyUtils.userDeviceHash(userId); - redisDataStore.setHashValue(userDeviceKey, deviceId, clientId); + cacheDataStore.setHashValue(userDeviceKey, deviceId, clientId); String deviceKey = RedisKeyUtils.deviceHash(deviceId); - redisDataStore.addSetValue(deviceKey, clientId); + cacheDataStore.addSetValue(deviceKey, clientId); } // Set the client's userId. - redisDataStore.setValue(RedisKeyUtils.client(clientId), userId); + cacheDataStore.setValue(RedisKeyUtils.client(clientId), userId); // Add to ClientUser list - redisDataStore.addSetValue(clientUserKey, clientId); + cacheDataStore.addSetValue(clientUserKey, clientId); if (Client.PERSISTENT_TYPE.equalsIgnoreCase(deviceType)) { - redisDataStore.addSetValue(RedisKeyUtils.clientsPersistent(), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientsPersistent(), clientId); } else { - redisDataStore.addSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); } } public Boolean isNonPersistentClient(String clientId) { - return redisDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId); + return cacheDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId); } public String getClientUserId(String clientId) { - return (String) redisDataStore.getValue(RedisKeyUtils.client(clientId)); + return (String) cacheDataStore.getValue(RedisKeyUtils.client(clientId)); } public Boolean findClientByClientIdUserId(String clientId, String userId) throws Exception { - return redisDataStore.getSetIsMember(RedisKeyUtils.clientUser(userId), clientId); + return cacheDataStore.getSetIsMember(RedisKeyUtils.clientUser(userId), clientId); } @SuppressWarnings("unchecked") public Set findClientByUserIdDeviceId(String userId, String deviceId) throws Exception { - Set deviceClientIds = (Set) redisDataStore.getSetValue(RedisKeyUtils.deviceHash(deviceId)); + Set deviceClientIds = (Set) cacheDataStore.getSetValue(RedisKeyUtils.deviceHash(deviceId)); if (deviceClientIds == null) { deviceClientIds = new HashSet(1); } - String result = (String) redisDataStore.getHashValue(RedisKeyUtils.userDeviceHash(userId), deviceId); + String result = (String) cacheDataStore.getHashValue(RedisKeyUtils.userDeviceHash(userId), deviceId); if (!StringUtils.hasText(result)) { deviceClientIds.add(result); } @@ -155,9 +155,9 @@ public Set findClientByUserIdDeviceId(String userId, String deviceId) th } public Boolean findClientByClientId(String clientId) { - if (redisDataStore.getSetIsMember(RedisKeyUtils.clientsPersistent(), clientId)) + if (cacheDataStore.getSetIsMember(RedisKeyUtils.clientsPersistent(), clientId)) return true; - else if (redisDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId)) + else if (cacheDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId)) return true; else return false; @@ -186,13 +186,13 @@ public Boolean validateClientByClientId(String clientId, Boolean setClientTimeou @SuppressWarnings("unchecked") public Set validateClients(Collection clientIds) throws Exception { - Set validClients = (Set) redisDataStore.getSetsContainsMembers(CLIENT_KEYS_SEY, clientIds.toArray()); + Set validClients = (Set) cacheDataStore.getSetsContainsMembers(CLIENT_KEYS_SEY, clientIds.toArray()); return validClients; } @SuppressWarnings("unchecked") public Set validateClientsIncludeFromDeviceHistory(Map clientDevices) throws Exception { - Set validClients = (Set) redisDataStore.getSetsContainsMembers(CLIENT_KEYS_SEY, clientDevices.keySet().toArray()); + Set validClients = (Set) cacheDataStore.getSetsContainsMembers(CLIENT_KEYS_SEY, clientDevices.keySet().toArray()); // Now check each device to see if it has a corresponding clientId. Iterator> itrClientDevices = clientDevices.entrySet().iterator(); @@ -201,7 +201,7 @@ public Set validateClientsIncludeFromDeviceHistory(Map c String nextClient = nextClientDevice.getKey(); String nextDevice = nextClientDevice.getValue(); - if (redisDataStore.getSetIsMember(RedisKeyUtils.deviceHash(nextDevice), nextClient)) { + if (cacheDataStore.getSetIsMember(RedisKeyUtils.deviceHash(nextDevice), nextClient)) { validClients.add(nextClient); } } @@ -217,9 +217,9 @@ public String validateAndRetrieveCurrentClientId(String clientId, String deviceI } else { // Client is NOT current, but could still be valid. - if (redisDataStore.getSetIsMember(RedisKeyUtils.deviceHash(deviceId), clientId)) { + if (cacheDataStore.getSetIsMember(RedisKeyUtils.deviceHash(deviceId), clientId)) { // Client IS valid, now get current Client. - Set validDeviceClientIds = (Set) redisDataStore.getSetValue(RedisKeyUtils.deviceHash(deviceId)); + Set validDeviceClientIds = (Set) cacheDataStore.getSetValue(RedisKeyUtils.deviceHash(deviceId)); Iterator itrValidDeviceClientIds = validDeviceClientIds.iterator(); while (itrValidDeviceClientIds.hasNext()) { String nextClientId = itrValidDeviceClientIds.next(); @@ -250,8 +250,8 @@ public void registerClient(String clientId, String userId, String deviceId, Stri if (!isValidClient) createClient(clientId, userId, deviceType, deviceId); - redisDataStore.addSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); - redisDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); + cacheDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); postClient(clientId); } @@ -263,8 +263,8 @@ public Boolean hibernateClient(String clientId, String userId) throws Exception // Make sure this client/user combo is a valid one. if (findClientByClientIdUserId(clientId, userId)) { // Remove the client from the LoggedIn list and add it to the Hibernated list. - redisDataStore.setHashValue(RedisKeyUtils.clientsHibernated(), clientId, System.currentTimeMillis()); - redisDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); + cacheDataStore.setHashValue(RedisKeyUtils.clientsHibernated(), clientId, System.currentTimeMillis()); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); // NOTE: The client is still in either the "client persistent" or "client non-persistent" list and // is therefore still considered a valid client. @@ -294,16 +294,16 @@ public Boolean upgradeClient(String clientId, String deviceId, String deviceType try { // Remove from NonPersistent list. - redisDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); // Add to Persistent List. - redisDataStore.addSetValue(RedisKeyUtils.clientsPersistent(), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientsPersistent(), clientId); // Add to LoggedIn list - redisDataStore.addSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); // Remove from Hibernated list - redisDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); + cacheDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); if (previousClientIds != null && !previousClientIds.isEmpty()) { Iterator itrPreviousClientIds = previousClientIds.iterator(); @@ -311,7 +311,7 @@ public Boolean upgradeClient(String clientId, String deviceId, String deviceType String nextPreviousClient = itrPreviousClientIds.next(); if (StringUtils.hasText(nextPreviousClient) && nextPreviousClient.equals(clientId)) { // Remove from NonPersistent list. - redisDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), nextPreviousClient); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), nextPreviousClient); renameClient(nextPreviousClient, clientId); } @@ -319,7 +319,7 @@ public Boolean upgradeClient(String clientId, String deviceId, String deviceType } else { // Add to ClientUser list - redisDataStore.addSetValue(RedisKeyUtils.clientUser(userId), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientUser(userId), clientId); } result = true; @@ -344,94 +344,94 @@ else if (thePreviousClient.equals(clientId)) { } // Get the existing UserId. - String userId = (String) redisDataStore.getValue(RedisKeyUtils.client(thePreviousClient)); + String userId = (String) cacheDataStore.getValue(RedisKeyUtils.client(thePreviousClient)); log.debug("Renaming client " + thePreviousClient + " to " + clientId); if (StringUtils.hasText(userId)) { log.debug("Renaming user " + userId + " from client " + thePreviousClient + " to " + clientId); // Remove Previous Client from ClientUser list - redisDataStore.removeSetValue(RedisKeyUtils.clientUser(userId), thePreviousClient); + cacheDataStore.removeSetValue(RedisKeyUtils.clientUser(userId), thePreviousClient); // Add to ClientUser list - redisDataStore.addSetValue(RedisKeyUtils.clientUser(userId), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientUser(userId), clientId); // Update the UserDevice ClientID. String userDeviceHashKey = RedisKeyUtils.userDeviceHash(userId); - Collection userDeviceKeys = redisDataStore.getHashKeys(userDeviceHashKey); + Collection userDeviceKeys = cacheDataStore.getHashKeys(userDeviceHashKey); Iterator itrUserDevices = userDeviceKeys.iterator(); while (itrUserDevices.hasNext()) { String nextDeviceKey = (String) itrUserDevices.next(); - if (thePreviousClient.equals(redisDataStore.getHashValue(userDeviceHashKey, nextDeviceKey))) { - redisDataStore.addSetValue(RedisKeyUtils.deviceHash(nextDeviceKey), clientId); - redisDataStore.setHashValue(userDeviceHashKey, nextDeviceKey, clientId); + if (thePreviousClient.equals(cacheDataStore.getHashValue(userDeviceHashKey, nextDeviceKey))) { + cacheDataStore.addSetValue(RedisKeyUtils.deviceHash(nextDeviceKey), clientId); + cacheDataStore.setHashValue(userDeviceHashKey, nextDeviceKey, clientId); } } // Set the Client's userId - redisDataStore.setValue(RedisKeyUtils.client(clientId), userId); + cacheDataStore.setValue(RedisKeyUtils.client(clientId), userId); // Remove the Previous Client's userId - redisDataStore.deleteKey(RedisKeyUtils.client(thePreviousClient)); + cacheDataStore.deleteKey(RedisKeyUtils.client(thePreviousClient)); } else { log.debug("Previous Client" + thePreviousClient + " has no corresponding UserID"); } // Swap NonPersistent list. - redisDataStore.swapSetValue(RedisKeyUtils.clientsNonPersistent(), thePreviousClient, clientId); + cacheDataStore.swapSetValue(RedisKeyUtils.clientsNonPersistent(), thePreviousClient, clientId); // Swap Persistent list. - redisDataStore.swapSetValue(RedisKeyUtils.clientsPersistent(), thePreviousClient, clientId); + cacheDataStore.swapSetValue(RedisKeyUtils.clientsPersistent(), thePreviousClient, clientId); // Swap LoggedIn list. - redisDataStore.swapSetValue(RedisKeyUtils.clientsLoggedIn(), thePreviousClient, clientId); + cacheDataStore.swapSetValue(RedisKeyUtils.clientsLoggedIn(), thePreviousClient, clientId); // Swap Hibernated list. - redisDataStore.swapHashKey(RedisKeyUtils.clientsHibernated(), thePreviousClient, clientId); + cacheDataStore.swapHashKey(RedisKeyUtils.clientsHibernated(), thePreviousClient, clientId); // Rename the UpdateJournals list. String prevUpdateJournalKey = RedisKeyUtils.updateJournal(thePreviousClient); - if (redisDataStore.hasKey(prevUpdateJournalKey)) { - if (!redisDataStore.renameIfAbsent(prevUpdateJournalKey, RedisKeyUtils.updateJournal(clientId))) { + if (cacheDataStore.hasKey(prevUpdateJournalKey)) { + if (!cacheDataStore.renameIfAbsent(prevUpdateJournalKey, RedisKeyUtils.updateJournal(clientId))) { // If new list already exists, then merge the two. - redisDataStore.setUnionAndStore(RedisKeyUtils.updateJournal(thePreviousClient), RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.updateJournal(clientId)); + cacheDataStore.setUnionAndStore(RedisKeyUtils.updateJournal(thePreviousClient), RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.updateJournal(clientId)); // Delete the old Key - redisDataStore.deleteKey(RedisKeyUtils.updateJournal(thePreviousClient)); + cacheDataStore.deleteKey(RedisKeyUtils.updateJournal(thePreviousClient)); } } // Rename the DeleteJournals list. String prevDeleteJournalKey = RedisKeyUtils.deleteJournal(thePreviousClient); - if (redisDataStore.hasKey(prevDeleteJournalKey)) { - if (!redisDataStore.renameIfAbsent(RedisKeyUtils.deleteJournal(thePreviousClient), RedisKeyUtils.deleteJournal(clientId))) { + if (cacheDataStore.hasKey(prevDeleteJournalKey)) { + if (!cacheDataStore.renameIfAbsent(RedisKeyUtils.deleteJournal(thePreviousClient), RedisKeyUtils.deleteJournal(clientId))) { // If new list already exists, then merge the two. - redisDataStore.setUnionAndStore(RedisKeyUtils.deleteJournal(thePreviousClient), RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.deleteJournal(clientId)); + cacheDataStore.setUnionAndStore(RedisKeyUtils.deleteJournal(thePreviousClient), RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.deleteJournal(clientId)); // Delete the old Key - redisDataStore.deleteKey(RedisKeyUtils.deleteJournal(thePreviousClient)); + cacheDataStore.deleteKey(RedisKeyUtils.deleteJournal(thePreviousClient)); } } // Merge sets of Access Journals. String prevClientAccessJournalKey = RedisKeyUtils.clientAccessJournal(thePreviousClient); - if (redisDataStore.hasKey(prevClientAccessJournalKey)) { - Set accessJournalIds = (Set)redisDataStore.getSetValue(prevClientAccessJournalKey); + if (cacheDataStore.hasKey(prevClientAccessJournalKey)) { + Set accessJournalIds = (Set)cacheDataStore.getSetValue(prevClientAccessJournalKey); Iterator itrAccessJournalIds = accessJournalIds.iterator(); while (itrAccessJournalIds.hasNext()) { String nextAccessJournalId = itrAccessJournalIds.next(); - redisDataStore.swapSetValue(RedisKeyUtils.accessJournal(nextAccessJournalId), thePreviousClient, clientId); + cacheDataStore.swapSetValue(RedisKeyUtils.accessJournal(nextAccessJournalId), thePreviousClient, clientId); } } - redisDataStore.setUnionAndStore(RedisKeyUtils.clientAccessJournal(clientId), RedisKeyUtils.clientAccessJournal(thePreviousClient), RedisKeyUtils.clientAccessJournal(clientId)); + cacheDataStore.setUnionAndStore(RedisKeyUtils.clientAccessJournal(clientId), RedisKeyUtils.clientAccessJournal(thePreviousClient), RedisKeyUtils.clientAccessJournal(clientId)); // Merge sets of ChangeWatchers. String prevWatcherClientKey = RedisKeyUtils.watcherClient(thePreviousClient); - if (redisDataStore.hasKey(prevWatcherClientKey)) { - Set changeWatcherIds = (Set)redisDataStore.getSetValue(prevWatcherClientKey); + if (cacheDataStore.hasKey(prevWatcherClientKey)) { + Set changeWatcherIds = (Set)cacheDataStore.getSetValue(prevWatcherClientKey); Iterator itrChangeWatcherIds = changeWatcherIds.iterator(); while (itrChangeWatcherIds.hasNext()) { String nextChangeWatcherId = itrChangeWatcherIds.next(); - redisDataStore.swapSetValue(nextChangeWatcherId, thePreviousClient, clientId); + cacheDataStore.swapSetValue(nextChangeWatcherId, thePreviousClient, clientId); } } - redisDataStore.setUnionAndStore(RedisKeyUtils.watcherClient(clientId), RedisKeyUtils.watcherClient(thePreviousClient), RedisKeyUtils.watcherClient(clientId)); + cacheDataStore.setUnionAndStore(RedisKeyUtils.watcherClient(clientId), RedisKeyUtils.watcherClient(thePreviousClient), RedisKeyUtils.watcherClient(clientId)); // // Rename the TransactionJournals list. // Collection transKeys = redisDataStore.keys(RedisKeyUtils.transactionJournal(clientId, "*")); @@ -454,10 +454,10 @@ public void logoutClient(String clientId, Boolean pleaseDestroyClient) { log.debug("Logging out client " + clientId + " [" + (pleaseDestroyClient != null && pleaseDestroyClient ? "T" : "F") + "]"); // Remove from LoggedIn Clients - redisDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); // Check to see if this is a non-persistent client type. - Boolean isNonPersistent = redisDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId); + Boolean isNonPersistent = cacheDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId); if (isNonPersistent || pleaseDestroyClient) { destroyClient(clientId); @@ -475,37 +475,37 @@ public void destroyClient(String clientId) { } // Get the client's userId. - String userId = (String) redisDataStore.getValue(RedisKeyUtils.client(clientId)); + String userId = (String) cacheDataStore.getValue(RedisKeyUtils.client(clientId)); Boolean validUser = StringUtils.hasText(userId); // Remove from ClientUser list if (validUser) { - redisDataStore.removeSetValue(RedisKeyUtils.clientUser(userId), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientUser(userId), clientId); } // Remove from Client's User ID. - redisDataStore.deleteKey(RedisKeyUtils.client(clientId)); + cacheDataStore.deleteKey(RedisKeyUtils.client(clientId)); // Remove from LoggedIn Clients - redisDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); // Remove from Hibernated Clients - redisDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); + cacheDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); // Remove from NonPersistent Clients - redisDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); // Remove from Persistent Clients - redisDataStore.removeSetValue(RedisKeyUtils.clientsPersistent(), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsPersistent(), clientId); // Delete all UpdateJournals for this Client. String updateJournalKey = RedisKeyUtils.updateJournal(clientId); // Set updateJournalIds = (Set)redisDataStore.getSetValue(updateJournalKey); // redisDataStore.removeSetsValue(updateJournalIds, clientId); - redisDataStore.deleteKey(updateJournalKey); + cacheDataStore.deleteKey(updateJournalKey); // Delete all DeleteJournals for this Client. - redisDataStore.deleteKey(RedisKeyUtils.deleteJournal(clientId)); + cacheDataStore.deleteKey(RedisKeyUtils.deleteJournal(clientId)); // // Delete all TransactionJournals for this Client. // Collection transJournalKeys = redisDataStore.keys(RedisKeyUtils.transactionJournal(clientId, "*")); @@ -514,25 +514,25 @@ public void destroyClient(String clientId) { // Delete Client's UserDevice. if (validUser) { String userDeviceHashKey = RedisKeyUtils.userDeviceHash(userId); - Collection userDeviceKeys = redisDataStore.getHashKeys(userDeviceHashKey); + Collection userDeviceKeys = cacheDataStore.getHashKeys(userDeviceHashKey); int originalSize = userDeviceKeys.size(); int countRemoved = 0; Iterator itrUserDevices = userDeviceKeys.iterator(); while (itrUserDevices.hasNext()) { String nextDeviceKey = (String) itrUserDevices.next(); - if (clientId.equals(redisDataStore.getHashValue(userDeviceHashKey, nextDeviceKey))) { + if (clientId.equals(cacheDataStore.getHashValue(userDeviceHashKey, nextDeviceKey))) { // Since the client id being destroyed, the whole device history related to this client is also to be destroyed. // However, as a safety precaution, set the expiration for the device hash. - redisDataStore.expire(RedisKeyUtils.deviceHash(nextDeviceKey), userDeviceTimeout, TimeUnit.SECONDS); - redisDataStore.removeSetValue(RedisKeyUtils.deviceHash(nextDeviceKey), clientId); - redisDataStore.deleteHashKey(userDeviceHashKey, nextDeviceKey); + cacheDataStore.expire(RedisKeyUtils.deviceHash(nextDeviceKey), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.removeSetValue(RedisKeyUtils.deviceHash(nextDeviceKey), clientId); + cacheDataStore.deleteHashKey(userDeviceHashKey, nextDeviceKey); countRemoved++; } } if (countRemoved >= originalSize) { // Remove the UserDevice Hash. - redisDataStore.deleteKey(userDeviceHashKey); + cacheDataStore.deleteKey(userDeviceHashKey); } } @@ -572,22 +572,22 @@ public void destroyClient(String clientId) { @Transactional private void deleteClientAccessJournals(String clientId) { String clientAccessJournalsKey = RedisKeyUtils.clientAccessJournal(clientId); - Set clientAccessJournals = (Set) redisDataStore.getSetValue(clientAccessJournalsKey); - redisDataStore.removeSetsValue(RedisKeyUtils.ACCESS_JOURNAL_PREFIX, clientAccessJournals, clientId); + Set clientAccessJournals = (Set) cacheDataStore.getSetValue(clientAccessJournalsKey); + cacheDataStore.removeSetsValue(RedisKeyUtils.ACCESS_JOURNAL_PREFIX, clientAccessJournals, clientId); // Now remove the Client's AccessJournal key. - redisDataStore.deleteKey(clientAccessJournalsKey); + cacheDataStore.deleteKey(clientAccessJournalsKey); } @SuppressWarnings("unchecked") @Transactional private void deleteClientWatchers(String clientId) { String watcherClientKey = RedisKeyUtils.watcherClient(clientId); - Set watcherClientIds = (Set) redisDataStore.getSetValue(watcherClientKey); - redisDataStore.removeSetsValue("", watcherClientIds, clientId); + Set watcherClientIds = (Set) cacheDataStore.getSetValue(watcherClientKey); + cacheDataStore.removeSetsValue("", watcherClientIds, clientId); // Now remove the Client's Watcher key. - redisDataStore.deleteKey(watcherClientKey); + cacheDataStore.deleteKey(watcherClientKey); } /** @@ -618,7 +618,7 @@ public void postAccessJournals() { Iterator itrAccessJournals = accessJournalsToDelete.iterator(); while (itrAccessJournals.hasNext()) { String nextAccessJournal = itrAccessJournals.next(); - Set accessJournalClients = (Set)redisDataStore.getSetValue(nextAccessJournal); + Set accessJournalClients = (Set)cacheDataStore.getSetValue(nextAccessJournal); if (accessJournalClients != null) { Set clientIdsToRemove = new HashSet(); @@ -637,7 +637,7 @@ else if (!findClientByClientId(nextClientId) || !StringUtils.hasText(getClientUs } if (!clientIdsToRemove.isEmpty()) { - redisDataStore.removeSetValues(nextAccessJournal, clientIdsToRemove); + cacheDataStore.removeSetValues(nextAccessJournal, clientIdsToRemove); } } } @@ -688,7 +688,7 @@ public void postClients() { } // Now check Hibernating clients to see if any of those need to be removed - Map hibernatingClients = redisDataStore.getHashEntries(RedisKeyUtils.clientsHibernated()); + Map hibernatingClients = cacheDataStore.getHashEntries(RedisKeyUtils.clientsHibernated()); Iterator> itrHibernatingClientsEntries = hibernatingClients.entrySet().iterator(); while (itrHibernatingClientsEntries.hasNext()) { Map.Entry nextEntry = itrHibernatingClientsEntries.next(); @@ -698,7 +698,7 @@ public void postClients() { } catch(Exception e) { // This is an invalid key, so remove it from the hash. try { - redisDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), nextEntry.getKey()); + cacheDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), nextEntry.getKey()); } catch(Exception e1) { log.error("Invalid hash key in " + RedisKeyUtils.clientsHibernated()); } @@ -711,7 +711,7 @@ public void postClients() { } catch(Exception e) { // This timeout is not in a valid format, set to current time and move on. try { - redisDataStore.setHashValue(RedisKeyUtils.clientsHibernated(), nextHibernatingClientId, nextEntry.getValue()); + cacheDataStore.setHashValue(RedisKeyUtils.clientsHibernated(), nextHibernatingClientId, nextEntry.getValue()); } catch(Exception e1) { log.error("Invalid hash value in " + RedisKeyUtils.clientsHibernated()); } @@ -757,7 +757,7 @@ public void saveUpdateJournalClients(ClassIDPair pair, Collection client } String key = RedisKeyUtils.updateJournal(nextClient); - redisDataStore.addSetValue(key, classValue); + cacheDataStore.addSetValue(key, classValue); } } catch(Exception e) { @@ -767,12 +767,12 @@ public void saveUpdateJournalClients(ClassIDPair pair, Collection client } public Long deleteUpdateJournal(String clientId, String className, String classId) { - return redisDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(className, classId)); + return cacheDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(className, classId)); } public void deleteUpdateJournals(String clientId, ClassIDPair[] objects) { for(ClassIDPair nextObject : objects) { - redisDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(nextObject.getClassName(), nextObject.getID())); + cacheDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(nextObject.getClassName(), nextObject.getID())); } } @@ -790,7 +790,7 @@ public void saveDeleteJournalClients(ClassIDPair pair, Collection client } String key = RedisKeyUtils.deleteJournal(nextClient); - redisDataStore.addSetValue(key, classValue); + cacheDataStore.addSetValue(key, classValue); } } catch(Exception e) { @@ -800,12 +800,12 @@ public void saveDeleteJournalClients(ClassIDPair pair, Collection client } public Long deleteDeleteJournal(String clientId, String className, String classId) { - return redisDataStore.removeSetValue(RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.classIdPair(className, classId)); + return cacheDataStore.removeSetValue(RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.classIdPair(className, classId)); } public void deleteDeleteJournals(String clientId, ClassIDPair[] objects) { for(ClassIDPair nextObject : objects) { - redisDataStore.removeSetValue(RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.classIdPair(nextObject.getClassName(), nextObject.getID())); + cacheDataStore.removeSetValue(RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.classIdPair(nextObject.getClassName(), nextObject.getID())); } } @@ -828,10 +828,10 @@ private Long upsertRedisAccessJournal(String userId, String clientId, String cla try { // Need to add the ObjectID to the Client's AccessJournals set. String clientAccessJournalKey = RedisKeyUtils.clientAccessJournal(clientId); - redisDataStore.addSetValue(clientAccessJournalKey, RedisKeyUtils.objectId(className, classId)); + cacheDataStore.addSetValue(clientAccessJournalKey, RedisKeyUtils.objectId(className, classId)); // Need to add the ClientID to the Object's AccessJournal set. - return redisDataStore.addSetValue(key, clientId); + return cacheDataStore.addSetValue(key, clientId); } catch(Exception e) { log.error("Unable to upsertRedisAccessJournal", e); } finally { @@ -867,7 +867,7 @@ public List getObjectAccessJournals(String className, String classId) th //moveAccessJournals(); // TODO: Use a class id map instead of class name for faster lookup. // Use hash of full class name to generate ID? - Set redisClassIdSet = (Set) redisDataStore.getSetUnion(objectAccessJournalKey, allObjectAccessJournalKey); + Set redisClassIdSet = (Set) cacheDataStore.getSetUnion(objectAccessJournalKey, allObjectAccessJournalKey); result.addAll(redisClassIdSet); // RedisKeyUtils.accessJournal(className, classId), // RedisKeyUtils.accessJournal(className, "0")); @@ -900,15 +900,15 @@ public Collection getClientUpdateJournals(String clientId, Boolean logge Collection updateJournalSet = null; if (loggedInOnly) { - if (redisDataStore.getSetIsMember(RedisKeyUtils.clientsLoggedIn(), clientId)) { - updateJournalSet = (Set) redisDataStore.getSetValue(key); + if (cacheDataStore.getSetIsMember(RedisKeyUtils.clientsLoggedIn(), clientId)) { + updateJournalSet = (Set) cacheDataStore.getSetValue(key); } else { updateJournalSet = new HashSet(0); } } else { - updateJournalSet = (Set) redisDataStore.getSetValue(key); + updateJournalSet = (Set) cacheDataStore.getSetValue(key); } return updateJournalSet; @@ -923,15 +923,15 @@ public Collection getClientDeleteJournals(String clientId, Boolean logge Collection deleteJournalSet = null; if (loggedInOnly) { - if (redisDataStore.getSetIsMember(RedisKeyUtils.clientsLoggedIn(), clientId)) { - deleteJournalSet = (Set) redisDataStore.getSetValue(key); + if (cacheDataStore.getSetIsMember(RedisKeyUtils.clientsLoggedIn(), clientId)) { + deleteJournalSet = (Set) cacheDataStore.getSetValue(key); } else { deleteJournalSet = new HashSet(0); } } else { - deleteJournalSet = (Set) redisDataStore.getSetValue(key); + deleteJournalSet = (Set) cacheDataStore.getSetValue(key); } return deleteJournalSet; @@ -942,7 +942,7 @@ public Collection getClientDeleteJournals(String clientId, Boolean logge */ public void removeUpdateJournals(String clientId, Collection updateJournalsToRemove) throws Exception { String key = RedisKeyUtils.updateJournal(clientId); - redisDataStore.removeSetValues(key, updateJournalsToRemove); + cacheDataStore.removeSetValues(key, updateJournalsToRemove); } /* (non-Javadoc) @@ -958,7 +958,7 @@ public void removeAccessJournalsByObject(ClassIDPair classIdPair) { String objectId = RedisKeyUtils.objectId(classIdPair.getClassName(), classIdPair.getID()); String accessJournalKey = RedisKeyUtils.accessJournal(classIdPair.getClassName(), classIdPair.getID()); - Set clientIds = (Set) redisDataStore.getSetValue(accessJournalKey); + Set clientIds = (Set) cacheDataStore.getSetValue(accessJournalKey); Set clientAccessJournalKeys = new HashSet(clientIds.size()); Iterator itrClientIds = clientIds.iterator(); while (itrClientIds.hasNext()) { @@ -968,7 +968,7 @@ public void removeAccessJournalsByObject(ClassIDPair classIdPair) { clientAccessJournalKeys.add(clientAccessJournalsKey); } - redisDataStore.removeSetsValue(clientAccessJournalKeys, objectId); + cacheDataStore.removeSetsValue(clientAccessJournalKeys, objectId); // Iterator itrClientIds = clientIds.iterator(); // while (itrClientIds.hasNext()) { @@ -984,15 +984,15 @@ public void removeAccessJournalsByObject(ClassIDPair classIdPair) { // } // Now delete the AccessJournal record. - redisDataStore.deleteKey(accessJournalKey); + cacheDataStore.deleteKey(accessJournalKey); } public void removeObjectModJournalsByObject(ClassIDPair classIdPair) { - redisDataStore.deleteKey(RedisKeyUtils.objectModJournal(classIdPair.getClassName(), classIdPair.getID())); + cacheDataStore.deleteKey(RedisKeyUtils.objectModJournal(classIdPair.getClassName(), classIdPair.getID())); } public void removeHistoricalObjectsByObject(ClassIDPair classIdPair) { - redisDataStore.deleteKey(RedisKeyUtils.historicalObject(classIdPair.getClassName(), classIdPair.getID())); + cacheDataStore.deleteKey(RedisKeyUtils.historicalObject(classIdPair.getClassName(), classIdPair.getID())); } @@ -1040,9 +1040,9 @@ public void addWatcherClient(ClassIDPair classIdPair, String fieldName, String c changeWatcherId = RedisKeyUtils.clientWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), fieldName)); // Add the ClientID to the ChangeWatcher client Set - redisDataStore.addSetValue(changeWatcherId, clientId); + cacheDataStore.addSetValue(changeWatcherId, clientId); // Also add the ChangeWatcher ID to the client ChangeWatcher Set - redisDataStore.addSetValue(RedisKeyUtils.watcherClient(clientId), changeWatcherId); + cacheDataStore.addSetValue(RedisKeyUtils.watcherClient(clientId), changeWatcherId); } public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Collection fieldsToWatch) { @@ -1071,10 +1071,10 @@ public void updateWatcherFields(String category, String subCategory, String fiel watcherField = RedisKeyUtils.watcherField(changeWatcherId); } - Collection watchedFields = (Set) redisDataStore.getSetValue(watcherField); + Collection watchedFields = (Set) cacheDataStore.getSetValue(watcherField); // Remove current set of fields to watch and replace with new set. - redisDataStore.replaceSet(watcherField, fieldsToWatch); + cacheDataStore.replaceSet(watcherField, fieldsToWatch); if (fieldsToWatch != null) { Iterator itrFieldsToWatch = fieldsToWatch.iterator(); @@ -1082,7 +1082,7 @@ public void updateWatcherFields(String category, String subCategory, String fiel String nextField = itrFieldsToWatch.next(); // Also add this ChangeWatcher from the FieldWatcher. - redisDataStore.addSetValue(nextField, changeWatcherId); + cacheDataStore.addSetValue(nextField, changeWatcherId); // Keep track of field that is being watched at an object level. String[] nextFieldArr = nextField.split(":"); @@ -1104,7 +1104,7 @@ public void updateWatcherFields(String category, String subCategory, String fiel } String objectWatchedFieldKey = RedisKeyUtils.objectWatchedFields(nextFieldClassName, nextFieldClassId); - redisDataStore.setHashValue(objectWatchedFieldKey, hashKey, nextField); + cacheDataStore.setHashValue(objectWatchedFieldKey, hashKey, nextField); } if (watchedFields != null) { @@ -1121,7 +1121,7 @@ public void updateWatcherFields(String category, String subCategory, String fiel String nextOldField = itrOldWatchedFields.next(); // Also remove this ChangeWatcher from the FieldWatcher. - redisDataStore.removeSetValue(nextOldField, changeWatcherId); + cacheDataStore.removeSetValue(nextOldField, changeWatcherId); } } } @@ -1134,7 +1134,7 @@ public void removeChangeWatchers(String category, String subCategory) { String categoryKey = RedisKeyUtils.changeWatcherClass(category, subCategory); // Get all change watcher values associated with this object. - Set changeWatcherValueKeys = redisDataStore.getHashKeys(categoryKey); + Set changeWatcherValueKeys = cacheDataStore.getHashKeys(categoryKey); Iterator itrChangeWatcherValueKeys = changeWatcherValueKeys.iterator(); while (itrChangeWatcherValueKeys.hasNext()) { String nextChangeWatcherValueKey = (String) itrChangeWatcherValueKeys.next(); @@ -1149,36 +1149,36 @@ public void removeChangeWatchers(String category, String subCategory) { // For every watcherField, find the corresponding set and remove this changeWatcherKey // from that set. String watcherField = RedisKeyUtils.watcherField(changeWatcherKey); - Set watcherFieldValues = (Set) redisDataStore.getSetValue(watcherField); + Set watcherFieldValues = (Set) cacheDataStore.getSetValue(watcherField); Iterator itrWatcherFieldValues = watcherFieldValues.iterator(); while (itrWatcherFieldValues.hasNext()) { String nextWatcherFieldValue = itrWatcherFieldValues.next(); - redisDataStore.removeSetValue(nextWatcherFieldValue, changeWatcherKey); + cacheDataStore.removeSetValue(nextWatcherFieldValue, changeWatcherKey); } String fieldWatcher = RedisKeyUtils.fieldWatcher(changeWatcherKey); // Now remove all keys associated with this Change Watcher Value. - redisDataStore.deleteKey(key); - redisDataStore.deleteKey(clientWatcherKey); - redisDataStore.deleteKey(watcherField); - redisDataStore.deleteKey(fieldWatcher); + cacheDataStore.deleteKey(key); + cacheDataStore.deleteKey(clientWatcherKey); + cacheDataStore.deleteKey(watcherField); + cacheDataStore.deleteKey(fieldWatcher); } } String objectWatchedFieldKey = RedisKeyUtils.objectWatchedFields(category, subCategory); - Set objectWatcherValueKeys = redisDataStore.getHashKeys(objectWatchedFieldKey); + Set objectWatcherValueKeys = cacheDataStore.getHashKeys(objectWatchedFieldKey); Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); while (itrObjectWatcherValueKeys.hasNext()) { String nextObjectWatcherValueKey = (String) itrObjectWatcherValueKeys.next(); // Get all fields for this object that are being watched and remove them. - String changeWatcherKey = (String) redisDataStore.getHashValue(objectWatchedFieldKey, nextObjectWatcherValueKey); - redisDataStore.deleteKey(changeWatcherKey); + String changeWatcherKey = (String) cacheDataStore.getHashValue(objectWatchedFieldKey, nextObjectWatcherValueKey); + cacheDataStore.deleteKey(changeWatcherKey); } - redisDataStore.deleteKey(objectWatchedFieldKey); // Removes ALL change watcher values for this Object. + cacheDataStore.deleteKey(objectWatchedFieldKey); // Removes ALL change watcher values for this Object. - redisDataStore.deleteKey(categoryKey); // Removes ALL change watcher values for this Object. + cacheDataStore.deleteKey(categoryKey); // Removes ALL change watcher values for this Object. } public void saveChangeWatcherResult(ClassIDPair classIdPair, String fieldName, Object result) { @@ -1192,7 +1192,7 @@ public void saveChangeWatcherResult(ClassIDPair classIdPair, String fieldName, O HashMap resultHash = new HashMap(); resultHash.put(RedisKeyUtils.changeWatcherValueTimestamp(fieldName, params), System.currentTimeMillis()); resultHash.put(RedisKeyUtils.changeWatcherValueResult(fieldName, params), result); - redisDataStore.setAllHashValues(classKey, resultHash); + cacheDataStore.setAllHashValues(classKey, resultHash); } public void removeChangeWatcherResult(ClassIDPair classIdPair, String fieldName) { @@ -1203,8 +1203,8 @@ public void removeChangeWatcherResult(ClassIDPair classIdPair, String fieldName) public void removeChangeWatcherResult(ClassIDPair classIdPair, String fieldName, String[] params) { String key = RedisKeyUtils.changeWatcherClass(classIdPair.getClassName(), classIdPair.getID()); - redisDataStore.deleteHashKey(key, RedisKeyUtils.changeWatcherValueTimestamp(fieldName, params)); - redisDataStore.deleteHashKey(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); + cacheDataStore.deleteHashKey(key, RedisKeyUtils.changeWatcherValueTimestamp(fieldName, params)); + cacheDataStore.deleteHashKey(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); } public Long getChangeWatcherResultTimestamp(ClassIDPair classIdPair, String fieldName) { @@ -1214,7 +1214,7 @@ public Long getChangeWatcherResultTimestamp(ClassIDPair classIdPair, String fiel public Long getChangeWatcherResultTimestamp(ClassIDPair classIdPair, String fieldName, String[] params) { String key = RedisKeyUtils.changeWatcherClass(classIdPair.getClassName(), classIdPair.getID()); - Long result = (Long) redisDataStore.getHashValue(key, RedisKeyUtils.changeWatcherValueTimestamp(fieldName, params)); + Long result = (Long) cacheDataStore.getHashValue(key, RedisKeyUtils.changeWatcherValueTimestamp(fieldName, params)); return result; } @@ -1269,7 +1269,7 @@ public Boolean getChangeWatcherResultExists(ClassIDPair classIdPair, String fiel public Boolean getChangeWatcherResultExists(ClassIDPair classIdPair, String fieldName, String[] params) { String key = RedisKeyUtils.changeWatcherClass(classIdPair.getClassName(), classIdPair.getID()); - Boolean hasKey = redisDataStore.hasHashKey(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); + Boolean hasKey = cacheDataStore.hasHashKey(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); return hasKey; } @@ -1281,7 +1281,7 @@ public Object getChangeWatcherResult(ClassIDPair classIdPair, String fieldName) public Object getChangeWatcherResult(ClassIDPair classIdPair, String fieldName, String[] params) { String key = RedisKeyUtils.changeWatcherClass(classIdPair.getClassName(), classIdPair.getID()); - return redisDataStore.getHashValue(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); + return cacheDataStore.getHashValue(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); } public void checkChangeWatchers(ClassIDPair classIdPair) { @@ -1357,7 +1357,7 @@ protected Collection getChangeWatchersForField(ClassIDPair classIdPair, Collection changeWatchers = null; if (fieldWatcherKeys.size() > 0) { - changeWatchers = (Set) redisDataStore.getSetUnion(null, fieldWatcherKeys); + changeWatchers = (Set) cacheDataStore.getSetUnion(null, fieldWatcherKeys); } return changeWatchers; @@ -1374,13 +1374,13 @@ protected Set getAllFieldWatchersForObject(ClassIDPair classIdPair) { for(int i=0; i objectWatcherValueKeys = redisDataStore.getHashKeys(nextKey); + Set objectWatcherValueKeys = cacheDataStore.getHashKeys(nextKey); Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); while (itrObjectWatcherValueKeys.hasNext()) { String nextObjectWatcherValueKey = (String) itrObjectWatcherValueKeys.next(); // Get all fields for this object that are being watched and remove them. - String changeWatcherKey = (String) redisDataStore.getHashValue(nextKey, nextObjectWatcherValueKey); + String changeWatcherKey = (String) cacheDataStore.getHashValue(nextKey, nextObjectWatcherValueKey); fieldWatcherKeys.add(changeWatcherKey); } } @@ -1415,7 +1415,7 @@ protected Long removeChangeWatcherForField(ClassIDPair classIdPair, String[] fie Iterator itrFieldWatcherKeys = fieldWatcherKeys.iterator(); while (itrFieldWatcherKeys.hasNext()) { String nextFieldWatcherKey = itrFieldWatcherKeys.next(); - Long countRemoved = redisDataStore.removeSetValue(nextFieldWatcherKey, changeWatcherId); + Long countRemoved = cacheDataStore.removeSetValue(nextFieldWatcherKey, changeWatcherId); result += countRemoved; } } @@ -1466,7 +1466,7 @@ public void recalculateChangeWatcher(String changeWatcherId) { if (changeWatcherHelperFactory != null) { - Collection clientIds = (Set) redisDataStore.getSetValue(RedisKeyUtils.clientWatcher(changeWatcherId)); // The list of ClientID's who are interested in this object. + Collection clientIds = (Set) cacheDataStore.getSetValue(RedisKeyUtils.clientWatcher(changeWatcherId)); // The list of ClientID's who are interested in this object. IChangeWatcherHelper cwh = changeWatcherHelperFactory.getHelper(category); cwh.reprocess(category, subCategory, fieldName, clientIds, otherParams, requestTimestamp); From fbbf45af12f018629b429c221a1dc4965571b1e7 Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Fri, 28 Aug 2015 07:10:28 -0700 Subject: [PATCH 05/20] Cleanup --- pom.xml | 2 +- .../sync/access/RedisAccessManager.java | 7 ------ .../agents/sync/cw/ChangeWatcherHelper.java | 10 ++++---- .../cw/DerivedValueChangeWatcherHelper.java | 24 +++++++++++++++---- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index ccca2fd..81381a4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.activestack + org.activestack syncengine 1.1.15-SNAPSHOT diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index 19f5706..86bc1f0 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -1471,13 +1471,6 @@ public void recalculateChangeWatcher(String changeWatcherId) { IChangeWatcherHelper cwh = changeWatcherHelperFactory.getHelper(category); cwh.reprocess(category, subCategory, fieldName, clientIds, otherParams, requestTimestamp); -// // If this is an Object Change Watcher, then build a ClassIDPair and run the recalc. -// if (false) { -// ClassIDPair pair = new ClassIDPair(subCategory, category); -// cwh.recalculate(fieldName, pair, clientIds, otherParams, requestTimestamp); -// } -// else { -// } /** // If no clients interested in this value, then remove it from the cache. if (clientIds == null || clientIds.isEmpty()) { diff --git a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java index 4329eee..75d8704 100644 --- a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java +++ b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java @@ -15,12 +15,14 @@ import com.percero.framework.vo.IPerceroObject; /** - * ChangeWatcherHelper allows code to be executed upon the change of any model data. The ChangeWatcherHelper is used - * as the mechanism to execute that code. A ChangeWatcherHelper must be registered with the ChangeWatcherHelperFactory. - * Ex: ChangeWatcherHelperFactory.getInstance().registerChangeWatcherHelper( "category", this ); + * ChangeWatcherHelper allows code to be executed upon the change of any model + * data. The ChangeWatcherHelper is used as the mechanism to execute that code. + * A ChangeWatcherHelper must be registered with the ChangeWatcherHelperFactory. + * Ex: ChangeWatcherHelperFactory.getInstance().registerChangeWatcherHelper( + * "category", this ); * * @author Collin Brown - * + * */ @Component public class ChangeWatcherHelper implements IChangeWatcherHelper { diff --git a/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java b/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java index 5340a5f..8f28c61 100644 --- a/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java +++ b/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java @@ -13,7 +13,6 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; -import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.hibernate.SyncHibernateUtils; import com.percero.agents.sync.metadata.IMappedClassManager; import com.percero.agents.sync.metadata.MappedClass; @@ -28,14 +27,31 @@ import com.percero.agents.sync.vo.PushCWUpdateResponse; import com.percero.framework.vo.IPerceroObject; +/** + * Customized Change Watcher for calculating Derived Values. Derived Values are + * properties on the data model that are derived from other properties and thus + * NOT stored in the data store. Derived Values are stored in the cache, along + * with the triggers necessary to recalculate them. + * + * For each Derived Value, a Change Watcher is meant to be set on each and every + * property that could potentially effect the resultant Derived Value. When one + * of those values changes, the Change Watcher will cause the Derived Value to + * be recalculated. Changes to a Derived Value are also automatically pushed out + * to all Clients who have registered interest in that Derived Value. + * + * Dynamic parameters can be used to register for a Derived Value. For example, + * a daily report roll-up could use the Date as part of the name of the Derived + * Value. These parameters are passed as part of the name (ie. identifier) of + * the Derived Value. + * + * @author Collin Brown + * + */ @Component public class DerivedValueChangeWatcherHelper extends ChangeWatcherHelper implements IChangeWatcherValueHelper { private static final Logger log = Logger.getLogger(ChangeWatcherHelper.class); -// @Autowired -// ObjectMapper objectMapper; - @Autowired protected IPushSyncHelper pushSyncHelper; public void setPushSyncHelper(IPushSyncHelper value) { From 0162c1b520cb6b48092536397774f15db9732a94 Mon Sep 17 00:00:00 2001 From: Jonathan Samples Date: Wed, 2 Sep 2015 08:41:41 -0700 Subject: [PATCH 06/20] Started on update table stuff --- .../agents/sync/jobs/ProcessorResult.java | 82 +++++++++++++++++ .../jobs/UpdateTableConnectionFactory.java | 88 +++++++++++++++++++ .../agents/sync/jobs/UpdateTablePoller.java | 50 +++++++++++ .../spring/percero-spring-config.xml | 1 + 4 files changed, 221 insertions(+) create mode 100644 src/main/java/com/percero/agents/sync/jobs/ProcessorResult.java create mode 100644 src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java create mode 100644 src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java diff --git a/src/main/java/com/percero/agents/sync/jobs/ProcessorResult.java b/src/main/java/com/percero/agents/sync/jobs/ProcessorResult.java new file mode 100644 index 0000000..7f577c9 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/jobs/ProcessorResult.java @@ -0,0 +1,82 @@ +package com.percero.agents.sync.jobs; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by jonnysamps on 8/31/15. + */ +public class ProcessorResult { + private int total; + private int numFailed; + + private boolean success = true; + private Map details = new HashMap(); + private Map> failures = new HashMap>(); + + public int getTotal() { + return total; + } + + public int getNumFailed(){ + return numFailed; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public Map getDetails() { + return details; + } + + public void addResult(String type, boolean wasSuccess, String message){ + total++; + if(!wasSuccess) { + success = false; + numFailed++; + if(!failures.containsKey(type)) failures.put(type, new ArrayList()); + failures.get(type).add(message); + } + else{ + if(!details.containsKey(type)) details.put(type, 0); + details.put(type, details.get(type)+1); + } + } + + /** + * @see ProcessorResult.addResult(String, boolean, String) + * @param type + */ + public void addResult(String type){ + this.addResult(type, true, null); + } + + /** + * Some niceties for logging + * @return + */ + public String toString(){ + StringBuilder sb = new StringBuilder(); + sb.append("Overall Success :"); sb.append(isSuccess()); sb.append("\n"); + sb.append("Total results :"); sb.append(getTotal()); sb.append("\n"); + sb.append("Total failures :"); sb.append(getNumFailed()); sb.append("\n"); + sb.append("Failures by type:"); sb.append("\n"); + for(String key : failures.keySet()){ + sb.append(" "); sb.append(key); sb.append(":"); sb.append("\n"); + int i = 1; + for(String message : failures.get(key)){ + sb.append(" "); sb.append(i); sb.append(": "); sb.append(message); sb.append("\n"); + i++; + } + } + + return sb.toString(); + } +} diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java new file mode 100644 index 0000000..747b09b --- /dev/null +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java @@ -0,0 +1,88 @@ +package com.percero.agents.sync.jobs; + +import com.mchange.v2.c3p0.ComboPooledDataSource; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.beans.PropertyVetoException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * Created by jonnysamps on 9/2/15. + */ +@Component +public class UpdateTableConnectionFactory { + + private static Logger logger = Logger.getLogger(UpdateTableConnectionFactory.class); + + @Autowired + @Value("pf{updateTable.driverClassName:com.mysql.jdbc.Driver") + private String driverClassName; + + @Autowired + @Value("pf{updateTable.username") + private String username; + + @Autowired + @Value("pf{updateTable.username") + private String password; + + @Autowired + @Value("pf{updateTable.jdbcUrl:jdbc:mysql://localhost/db") + private String jdbcUrl; + + private ComboPooledDataSource cpds; + @PostConstruct + public void init() throws PropertyVetoException{ + try { + cpds = new ComboPooledDataSource(); + cpds.setDriverClass(driverClassName); //loads the jdbc driver + cpds.setJdbcUrl(jdbcUrl); + cpds.setUser(username); + cpds.setPassword(password); + +// the settings below are optional -- c3p0 can work with defaults + cpds.setMinPoolSize(5); + cpds.setAcquireIncrement(5); + cpds.setMaxPoolSize(20); + + }catch(PropertyVetoException pve){ + logger.error(pve.getMessage(), pve); + throw pve; + } + } + + public Connection getConnection() throws SQLException{ + try{ + return cpds.getConnection(); + }catch(SQLException e){ + logger.error(e.getMessage(), e); + throw e; + } + } + + public static void main(String[] args) throws Exception{ + UpdateTableConnectionFactory cf = new UpdateTableConnectionFactory(); + cf.driverClassName = "com.mysql.jdbc.Driver"; + cf.jdbcUrl = "jdbc:mysql://localhost/test"; + cf.username = "root"; + cf.password = "root"; + cf.init(); + + Connection c = cf.getConnection(); + Statement stmt = c.createStatement(); + + + ResultSet rs = stmt.executeQuery("SELECT * FROM Account"); + while(rs.next()) { + logger.info("ID: " + rs.getInt("ID")); + logger.info("markedForRemoval: "+ rs.getDate("markedForRemoval")); + } + } +} diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java new file mode 100644 index 0000000..65e5e5e --- /dev/null +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java @@ -0,0 +1,50 @@ +package com.percero.agents.sync.jobs; + +import com.mchange.v2.c3p0.ComboPooledDataSource; +import org.apache.log4j.Logger; +import org.hibernate.SessionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * Created by jonnysamps on 8/31/15. + */ +@Component +public class UpdateTablePoller { + + private static Logger logger = Logger.getLogger(UpdateTablePoller.class); + + private String[] tableNames = new String[0]; + @Autowired + @Value("$pf{updateTable.tableNames}") + public void setTableNames(String val){ + tableNames = val.split(","); + } + + + @Autowired + UpdateTableConnectionFactory connectionFactory; + + /** + * Run every minute + */ + @Scheduled(fixedDelay=6000, initialDelay=6000) + public void pollUpdateTables(){ + logger.info("Polling Update Tables..."); + for(String tableName : tableNames){ + UpdateTableProcessor processor = new UpdateTableProcessor(tableName, connectionFactory); + ProcessorResult result = processor.process(); + if(result.isSuccess()){ + logger.debug("Update table processor ("+tableName+") finished successfully. Total rows ("+result.getTotal()+")"); + } + else{ + logger.warn("Update table processor ("+tableName+") failed. Details:"); + logger.warn(result); + } + } + } + + +} diff --git a/src/main/resources/spring/percero-spring-config.xml b/src/main/resources/spring/percero-spring-config.xml index a7f0cff..6f3b4fb 100644 --- a/src/main/resources/spring/percero-spring-config.xml +++ b/src/main/resources/spring/percero-spring-config.xml @@ -44,6 +44,7 @@ + From 4c027687ccee3219d0db049510ee8efd3cf93e22 Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Thu, 3 Sep 2015 09:08:01 -0700 Subject: [PATCH 07/20] wip --- pom.xml | 2 +- .../pulse/service/PulseHttpAuthProvider.java | 188 -- .../service/PulseHttpAuthProviderFactory.java | 40 - .../com/convergys/pulse/vo/PulseUserInfo.java | 26 - .../dao/ActiveStackHibernateSqlQuery.java | 87 + .../dao/ActiveStackHibernateSqlSession.java | 31 + .../dao/ActiveStackSqlSessionFactory.java | 38 + .../agents/sync/dao/IActiveStackSqlQuery.java | 23 + .../sync/dao/IActiveStackSqlSession.java | 8 + .../agents/sync/dao/IDataAccessObject.java | 37 + .../sync/exceptions/SyncDataException.java | 4 + .../agents/sync/exceptions/SyncException.java | 6 + .../agents/sync/metadata/JpqlQuery.java | 12 + .../agents/sync/metadata/MappedClass.java | 151 +- .../agents/sync/metadata/MappedField.java | 14 + .../agents/sync/metadata/MappedFieldBool.java | 6 + .../sync/metadata/MappedFieldBoolean.java | 6 + .../agents/sync/metadata/MappedFieldDate.java | 6 + .../sync/metadata/MappedFieldDouble.java | 6 + .../sync/metadata/MappedFieldFloat.java | 6 + .../agents/sync/metadata/MappedFieldInt.java | 6 + .../sync/metadata/MappedFieldInteger.java | 6 + .../agents/sync/metadata/MappedFieldList.java | 7 + .../agents/sync/metadata/MappedFieldMap.java | 8 + .../metadata/MappedFieldPerceroObject.java | 30 +- .../sync/metadata/MappedFieldString.java | 8 + .../agents/sync/metadata/MappedQuery.java | 149 +- .../agents/sync/metadata/QueryFactory.java | 14 +- .../agents/sync/metadata/SqlQuery.java | 38 + .../agents/sync/services/DAODataProvider.java | 2048 +++++++++++++++++ .../agents/sync/services/DAORegistry.java | 37 + .../sync/services/HibernateDataProvider.java | 1688 ++++++++++++++ .../agents/sync/services/IDataProvider.java | 17 + .../percero/amqp/PerceroAgentListener.java | 9 + .../framework/metadata/IMappedQuery.java | 6 +- 35 files changed, 4451 insertions(+), 317 deletions(-) delete mode 100644 src/main/java/com/convergys/pulse/service/PulseHttpAuthProvider.java delete mode 100644 src/main/java/com/convergys/pulse/service/PulseHttpAuthProviderFactory.java delete mode 100644 src/main/java/com/convergys/pulse/vo/PulseUserInfo.java create mode 100644 src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlQuery.java create mode 100644 src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlSession.java create mode 100644 src/main/java/com/percero/agents/sync/dao/ActiveStackSqlSessionFactory.java create mode 100644 src/main/java/com/percero/agents/sync/dao/IActiveStackSqlQuery.java create mode 100644 src/main/java/com/percero/agents/sync/dao/IActiveStackSqlSession.java create mode 100644 src/main/java/com/percero/agents/sync/dao/IDataAccessObject.java create mode 100644 src/main/java/com/percero/agents/sync/services/DAODataProvider.java create mode 100644 src/main/java/com/percero/agents/sync/services/DAORegistry.java create mode 100644 src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java diff --git a/pom.xml b/pom.xml index bebe8ec..4f6d45e 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.activestack syncengine - 1.1.15-SNAPSHOT + 1.1.16-SNAPSHOT 3.2.4.RELEASE diff --git a/src/main/java/com/convergys/pulse/service/PulseHttpAuthProvider.java b/src/main/java/com/convergys/pulse/service/PulseHttpAuthProvider.java deleted file mode 100644 index 8c9e3ad..0000000 --- a/src/main/java/com/convergys/pulse/service/PulseHttpAuthProvider.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.convergys.pulse.service; - -import com.percero.agents.auth.services.IAuthProvider; -import com.percero.agents.auth.vo.BasicAuthCredential; -import com.convergys.pulse.vo.PulseUserInfo; -import com.percero.agents.auth.vo.ServiceIdentifier; -import com.percero.agents.auth.vo.ServiceUser; -import com.percero.serial.map.SafeObjectMapper; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.SingleClientConnManager; -import org.apache.log4j.Logger; -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.map.JsonMappingException; -import org.codehaus.jackson.map.ObjectMapper; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; -import java.io.IOException; -import java.security.SecureRandom; -import java.security.cert.X509Certificate; -import java.util.HashMap; -import java.util.Map; - -/** - * AuthProvider implementation for Pulse to their http rest endpoint - * Created by Jonathan Samples on 8/27/15. - */ -public class PulseHttpAuthProvider implements IAuthProvider { - - private static Logger logger = Logger.getLogger(PulseHttpAuthProvider.class); - private static final String ID = "pulse_http"; - - public String getID() { - return ID; - } - - /** - * @param credential - String in : format - * @return - */ - public ServiceUser authenticate(String credential) { - ServiceUser result = null; - BasicAuthCredential cred = BasicAuthCredential.fromString(credential); - - String endpoint = hostPortAndContext +"/Authenticate"; - Map params = new HashMap(); - params.put("userDomainAndLogin", cred.getUsername()); - params.put("userPassword", cred.getPassword()); - - String body = makeRequest(endpoint, params); - - /** - * Result will be something like - * true - */ - if(body.contains("true")){ - endpoint = hostPortAndContext+"/retrieve_user"; - params = new HashMap(); - params.put("userName", cred.getUsername()); - - body = makeRequest(endpoint, params); - logger.info(body); - - try { - PulseUserInfo pulseUserInfo = objectMapper.readValue(body, PulseUserInfo.class); - result = new ServiceUser(); - result.setId(pulseUserInfo.getEmployeeId()); - result.setFirstName(pulseUserInfo.getUserLogin()); - result.setAreRoleNamesAccurate(true); - result.getIdentifiers().add(new ServiceIdentifier("pulseUserLogin", pulseUserInfo.getUserLogin())); - // Uncomment this line when we start getting non-static employeeIds... or never, it shouldn't matter - // result.getIdentifiers().add(new ServiceIdentifier("pulseEmployeeId", pulseUserInfo.getEmployeeId())); - } - catch(JsonMappingException jme){ logger.warn(jme.getMessage(), jme); } - catch(JsonParseException jpe){ logger.warn(jpe.getMessage(), jpe); } - catch(IOException ioe){ logger.warn(ioe.getMessage(), ioe); } - } - - return result; - } - - /** - * @param url - * @param params - * @return - */ - private String makeRequest(String url, Map params){ - String body = ""; - try { - HttpClient client = getHttpClient(); - String query = "?"; - for(String key : params.keySet()){ - query += key+"="+params.get(key)+"&"; - } - url += query; - - HttpGet request = new HttpGet(url); - HttpResponse response = client.execute(request); - logger.debug("Got response from auth hostPortAndContext: (" + response.getStatusLine().getStatusCode() + ")" + response.getStatusLine().getReasonPhrase()); - body = IOUtils.toString(response.getEntity().getContent(), "UTF8"); - } catch(ClientProtocolException e){ - logger.warn(e.getMessage(), e); - } catch(IOException ioe){ - logger.warn(ioe.getMessage(), ioe); - } - - return body; - } - - private HttpClient getHttpClient(){ - HttpClient httpClient = null; - if(trustAllCerts) { - try { - SSLContext sslContext = SSLContext.getInstance("SSL"); - - // set up a TrustManager that trusts everything - sslContext.init(null, new TrustManager[]{new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(X509Certificate[] certs, - String authType) { - } - - public void checkServerTrusted(X509Certificate[] certs, - String authType) { - } - }}, new SecureRandom()); - - SSLSocketFactory sf = new SSLSocketFactory(sslContext); - Scheme httpsScheme = new Scheme("https", sf, 443); - SchemeRegistry schemeRegistry = new SchemeRegistry(); - schemeRegistry.register(httpsScheme); - - ClientConnectionManager cm = new SingleClientConnManager(null, schemeRegistry); - httpClient = new DefaultHttpClient(cm, null); - } catch (Exception e) { - logger.error(e.getMessage(), e); - } - } - - // If don't trustAllCerts or an exception thrown then use the default one. - if(httpClient == null){ - httpClient = new DefaultHttpClient(); - } - - return httpClient; - } - - private String hostPortAndContext; - private ObjectMapper objectMapper; - - /** - * Only make this true for development when dealing with a self-signed certificate - */ - private boolean trustAllCerts = false; - - /** - * @param hostPortAndContext - e.g. https://some_host:5400/auth - * @param objectMapper - */ - public PulseHttpAuthProvider(String hostPortAndContext, ObjectMapper objectMapper, boolean trustAllCerts){ - this.hostPortAndContext = hostPortAndContext; - this.objectMapper = objectMapper; - this.trustAllCerts = trustAllCerts; - } - - /** - * For Testing - * @param args - */ - public static void main(String[] args){ - PulseHttpAuthProvider provider = new PulseHttpAuthProvider("https://localhost:8900/auth", new SafeObjectMapper(), true); - ServiceUser su = provider.authenticate("hoo:ha"); - System.out.println(su.toString()); - } -} diff --git a/src/main/java/com/convergys/pulse/service/PulseHttpAuthProviderFactory.java b/src/main/java/com/convergys/pulse/service/PulseHttpAuthProviderFactory.java deleted file mode 100644 index fbbffcc..0000000 --- a/src/main/java/com/convergys/pulse/service/PulseHttpAuthProviderFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.convergys.pulse.service; - -import com.percero.agents.auth.services.AuthProviderRegistry; -import org.apache.log4j.Logger; -import org.codehaus.jackson.map.ObjectMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import javax.annotation.PostConstruct; - -/** - * Created by jonnysamps on 8/27/15. - */ -@Component -public class PulseHttpAuthProviderFactory { - - private static Logger logger = Logger.getLogger(PulseHttpAuthProviderFactory.class); - - @Autowired @Value("$pf{pulseHttpAuth.hostPortAndContext}") - String hostPortAndContext = null; - - @Autowired @Value("$pf{pulseHttpAuth.trustAllCerts:false}") - Boolean trustAllCerts = false; - - @Autowired - AuthProviderRegistry authProviderRegistry; - - @Autowired - ObjectMapper objectMapper; - - @PostConstruct - public void init(){ - if(hostPortAndContext != null){ - logger.info("Using PulseHttpAuthProvider with endpoint: "+hostPortAndContext); - PulseHttpAuthProvider provider = new PulseHttpAuthProvider(hostPortAndContext, objectMapper, trustAllCerts); - authProviderRegistry.addProvider(provider); - } - } -} diff --git a/src/main/java/com/convergys/pulse/vo/PulseUserInfo.java b/src/main/java/com/convergys/pulse/vo/PulseUserInfo.java deleted file mode 100644 index 13e6629..0000000 --- a/src/main/java/com/convergys/pulse/vo/PulseUserInfo.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.convergys.pulse.vo; - -/** - * Class to represent the response from the Pulse /retrieve_user endpoint - * Created by Jonathan Samples on 8/27/15. - */ -public class PulseUserInfo { - private String userLogin; - private String employeeId; - - public String getEmployeeId() { - return employeeId; - } - - public void setEmployeeId(String employeeId) { - this.employeeId = employeeId; - } - - public String getUserLogin() { - return userLogin; - } - - public void setUserLogin(String userLogin) { - this.userLogin = userLogin; - } -} diff --git a/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlQuery.java b/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlQuery.java new file mode 100644 index 0000000..a2fc2eb --- /dev/null +++ b/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlQuery.java @@ -0,0 +1,87 @@ +package com.percero.agents.sync.dao; + +import java.util.Collection; +import java.util.Date; +import java.util.List; + +import org.hibernate.SQLQuery; + +public class ActiveStackHibernateSqlQuery implements IActiveStackSqlQuery { + + private SQLQuery query; + + public ActiveStackHibernateSqlQuery(SQLQuery query) { + this.query = query; + } + + public String getQueryString() { + return getQuery().getQueryString(); + } + + @Override + public String[] getNamedParameters() { + return getQuery().getNamedParameters(); + } + + public IActiveStackSqlQuery setString(int position, String val) { + getQuery().setString(position, val); + return this; + } + + public IActiveStackSqlQuery setString(String name, String val) { + getQuery().setString(name, val); + return this; + } + + public IActiveStackSqlQuery setDate(int position, Date val) { + getQuery().setDate(position, val); + return this; + } + + public IActiveStackSqlQuery setDate(String name, Date val) { + getQuery().setDate(name, val); + return this; + } + + public IActiveStackSqlQuery setParameter(int position, Object val) { + getQuery().setParameter(position, val); + return this; + } + + public IActiveStackSqlQuery setParameter(String name, Object val) { + getQuery().setParameter(name, val); + return this; + } + + public IActiveStackSqlQuery setParameterList(String name, Collection vals) { + getQuery().setParameterList(name, vals); + return this; + } + + public IActiveStackSqlQuery setParameterList(String name, Object[] vals) { + getQuery().setParameterList(name, vals); + return this; + } + + public List list() { + return getQuery().list(); + } + + public Object uniqueResult() { + return getQuery().uniqueResult(); + } + + public int executeUpdate() { + return getQuery().executeUpdate(); + } + + + public SQLQuery getQuery() { + return query; + } + + public void setQuery(SQLQuery query) { + this.query = query; + } + +} diff --git a/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlSession.java b/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlSession.java new file mode 100644 index 0000000..d6b7a6d --- /dev/null +++ b/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlSession.java @@ -0,0 +1,31 @@ +package com.percero.agents.sync.dao; + +import org.hibernate.Session; + +public class ActiveStackHibernateSqlSession implements IActiveStackSqlSession { + + private Session session; + + public ActiveStackHibernateSqlSession(Session session) { + this.session = session; + } + + public IActiveStackSqlQuery createSQLQuery(String queryString) { + ActiveStackHibernateSqlQuery query = new ActiveStackHibernateSqlQuery(getSession().createSQLQuery(queryString)); + return query; + } + + public void close() { + if (getSession() != null) { + getSession().close(); + } + } + + public Session getSession() { + return session; + } + + public void setSession(Session session) { + this.session = session; + } +} diff --git a/src/main/java/com/percero/agents/sync/dao/ActiveStackSqlSessionFactory.java b/src/main/java/com/percero/agents/sync/dao/ActiveStackSqlSessionFactory.java new file mode 100644 index 0000000..5231c12 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/dao/ActiveStackSqlSessionFactory.java @@ -0,0 +1,38 @@ +package com.percero.agents.sync.dao; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import com.percero.agents.sync.exceptions.SyncDataException; + +@Component +public class ActiveStackSqlSessionFactory { + + private static ActiveStackSqlSessionFactory instance = null; + public static ActiveStackSqlSessionFactory getInstance() throws SyncDataException { + if (instance != null) { + return instance; + } + + throw new SyncDataException("No Session Factory", -1001); + } + + public ActiveStackSqlSessionFactory() { + ActiveStackSqlSessionFactory.instance = this; + } + + @Autowired + @Qualifier(value="appSessionFactory") + SessionFactory appSessionFactory; + public void setAppSessionFactory(SessionFactory value) { + appSessionFactory = value; + } + + public IActiveStackSqlSession retrieveOpenSession(String dataSource) { + ActiveStackHibernateSqlSession session = new ActiveStackHibernateSqlSession(appSessionFactory.openSession()); + return session; + } +} diff --git a/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlQuery.java b/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlQuery.java new file mode 100644 index 0000000..400c960 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlQuery.java @@ -0,0 +1,23 @@ +package com.percero.agents.sync.dao; + +import java.util.Collection; +import java.util.Date; +import java.util.List; + +public interface IActiveStackSqlQuery { + + public String getQueryString(); + public String[] getNamedParameters(); + public IActiveStackSqlQuery setString(int position, String val); + public IActiveStackSqlQuery setString(String name, String val); + public IActiveStackSqlQuery setDate(int position, Date val); + public IActiveStackSqlQuery setDate(String name, Date val); + public IActiveStackSqlQuery setParameter(int position, Object val); + public IActiveStackSqlQuery setParameter(String name, Object val); + public IActiveStackSqlQuery setParameterList(String name, Collection vals); + public IActiveStackSqlQuery setParameterList(String name, Object[] vals); + public List list(); + public Object uniqueResult(); + public int executeUpdate(); + +} diff --git a/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlSession.java b/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlSession.java new file mode 100644 index 0000000..afa874a --- /dev/null +++ b/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlSession.java @@ -0,0 +1,8 @@ +package com.percero.agents.sync.dao; + +public interface IActiveStackSqlSession { + + public IActiveStackSqlQuery createSQLQuery(String queryString); + + public void close(); +} diff --git a/src/main/java/com/percero/agents/sync/dao/IDataAccessObject.java b/src/main/java/com/percero/agents/sync/dao/IDataAccessObject.java new file mode 100644 index 0000000..4f4914b --- /dev/null +++ b/src/main/java/com/percero/agents/sync/dao/IDataAccessObject.java @@ -0,0 +1,37 @@ +package com.percero.agents.sync.dao; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import com.percero.agents.sync.exceptions.SyncException; +import com.percero.agents.sync.metadata.MappedField; +import com.percero.agents.sync.vo.ClassIDPair; +import com.percero.agents.sync.vo.ClassIDPairs; +import com.percero.framework.vo.IPerceroObject; +import com.percero.framework.vo.PerceroList; + +public interface IDataAccessObject { + + Boolean hasCreateAccess(ClassIDPair classIdPair, String userId); + Boolean hasReadAccess(ClassIDPair classIdPair, String userId); + Boolean hasUpdateAccess(ClassIDPair classIdPair, String userId); + Boolean hasDeleteAccess(ClassIDPair classIdPair, String userId); + + PerceroList getAll(Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception; + + List getAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException; + + List findByExample(T theQueryObject, List excludeProperties) throws SyncException; + + T retrieveObject(ClassIDPair classIdPair, String userId, Boolean shellOnly) throws SyncException; + + List retrieveObjects(ClassIDPairs classIdPairs, String userId, Boolean shellOnly) throws SyncException; + + Boolean createObject(T percero, String userIdObject) throws SyncException; + + Boolean updateObject(T perceroObject, Map> changedFields, String userId) throws SyncException; + + Boolean deleteObject(ClassIDPair classIdPair, String userIdObject) throws SyncException; + +} diff --git a/src/main/java/com/percero/agents/sync/exceptions/SyncDataException.java b/src/main/java/com/percero/agents/sync/exceptions/SyncDataException.java index 2bd4344..fba1fa9 100644 --- a/src/main/java/com/percero/agents/sync/exceptions/SyncDataException.java +++ b/src/main/java/com/percero/agents/sync/exceptions/SyncDataException.java @@ -32,6 +32,10 @@ public SyncDataException(String name, Integer code) { super(name, code); } + public SyncDataException(Exception e) { + super(e); + } + public SyncDataException() { super(); } diff --git a/src/main/java/com/percero/agents/sync/exceptions/SyncException.java b/src/main/java/com/percero/agents/sync/exceptions/SyncException.java index 67eb048..d3ed1ca 100644 --- a/src/main/java/com/percero/agents/sync/exceptions/SyncException.java +++ b/src/main/java/com/percero/agents/sync/exceptions/SyncException.java @@ -12,6 +12,8 @@ public class SyncException extends Exception { public static final Integer INVALID_CLIENT_USER_CODE = -102; public static final String RUN_PROCESS_ERROR = "runProcessError"; public static final Integer RUN_PROCESS_ERROR_CODE = -103; + public static final String MISSING_MAPPED_CLASS_ERROR = "missingMappedClass"; + public static final Integer MISSING_MAPPED_CLASS_ERROR_CODE = -104; public SyncException(String name, Integer code, String desc, Throwable t) { @@ -32,6 +34,10 @@ public SyncException(String name, Integer code) { this.setCode(code); } + public SyncException(Exception e) { + super(e); + } + public SyncException() { super(); } diff --git a/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java b/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java index a5ef179..264ceb2 100644 --- a/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java +++ b/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java @@ -1,5 +1,8 @@ package com.percero.agents.sync.metadata; +import org.hibernate.Query; +import org.hibernate.impl.SessionImpl; + public class JpqlQuery extends MappedQuery { @Override @@ -9,4 +12,13 @@ public void setQuery(String value) { value = value.substring(index + 5); super.setQuery(value); } + + @Override + public Query createQuery(Object theObject, String userId, Object[] params, + SessionImpl s) throws Exception { + Query theQuery = s.createQuery(getQuery()); + setQueryParameters(theQuery, theObject, userId, params, s); + + return theQuery; + } } diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedClass.java b/src/main/java/com/percero/agents/sync/metadata/MappedClass.java index dfc3feb..8cdb5db 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedClass.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedClass.java @@ -19,6 +19,7 @@ import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; @@ -46,6 +47,8 @@ import com.percero.agents.sync.metadata.annotations.PropertyInterfaces; import com.percero.agents.sync.metadata.annotations.RelationshipInterface; import com.percero.agents.sync.metadata.annotations.RelationshipInterfaces; +import com.percero.agents.sync.services.DataProviderManager; +import com.percero.agents.sync.services.IDataProvider; import com.percero.framework.bl.IManifest; import com.percero.framework.bl.ManifestHelper; import com.percero.framework.metadata.IMappedClass; @@ -160,12 +163,38 @@ else if (getReadAllQuery() != null) { public Boolean queriesInitialized = false; public Boolean relationshipsInitialized = false; // private Boolean isInitializing = false; + public String dataProviderName = ""; + public String getDataProviderName() { + return dataProviderName; + } + public void setDataProviderName(String dataProviderName) { + this.dataProviderName = dataProviderName; + + // Reset the DataProvider + if (dataProvider != null) { + dataProvider = null; + } + } + public String className = ""; public String tableName = ""; + public String tableSchema = ""; + public MappedField idMappedField = null; public List requiredFields = Collections.synchronizedList(new ArrayList()); + public Set toManyFields = Collections.synchronizedSet(new HashSet()); - public Set toOneFields = Collections.synchronizedSet(new HashSet()); + public Set toOneFields = Collections.synchronizedSet(new HashSet()); + + private Set sourceMappedFields = Collections.synchronizedSet(new HashSet()); + public Set getSourceMappedFields() { + return sourceMappedFields; + } + private Set targetMappedFields = Collections.synchronizedSet(new HashSet()); + public Set getTargetMappedFields() { + return targetMappedFields; + } + public Set propertyFields = Collections.synchronizedSet(new HashSet()); public List entityFields = Collections.synchronizedList(new ArrayList()); public List mapFields = Collections.synchronizedList(new ArrayList()); @@ -184,6 +213,15 @@ public List getChildMappedClasses() { } + IDataProvider dataProvider = null; + public IDataProvider getDataProvider() { + if (dataProvider == null) { + dataProvider = DataProviderManager.dataProviderManager.getDataProviderByName(dataProviderName); + } + return dataProvider; + } + + /** * readAccessRightsFieldReferences holds all MappedFields that have some sort of * readAccessRights associated with that field. This means that this field needs @@ -195,7 +233,7 @@ public List getChildMappedClasses() { public Set getReadAccessRightsFieldReferences() { return readAccessRightsFieldReferences; } - public List uniqueConstraints = new ArrayList(); + public List> uniqueConstraints = new ArrayList>(); public List queries = new ArrayList(); public Boolean hasGeneratedId = false; public Boolean hasNonLazyLoadProperties = false; @@ -428,17 +466,36 @@ else if (implementsInterface(nextFieldClass, List.class)) OneToMany oneToMany = (OneToMany) theGetter.getAnnotation(OneToMany.class); if (oneToMany == null) oneToMany = (OneToMany) nextField.getAnnotation(OneToMany.class); - if (oneToMany != null) { toManyFields.add(nextMappedField); + getTargetMappedFields().add(nextMappedField); } + ManyToOne manyToOne = (ManyToOne) theGetter.getAnnotation(ManyToOne.class); + if (manyToOne == null) + manyToOne = (ManyToOne) nextField.getAnnotation(ManyToOne.class); + if (manyToOne != null) { + getSourceMappedFields().add((MappedFieldPerceroObject) nextMappedField); + } + + OneToOne oneToOne = (OneToOne) theGetter.getAnnotation(OneToOne.class); + if (oneToOne == null) + oneToOne = (OneToOne) nextField.getAnnotation(OneToOne.class); + if (oneToOne != null) { + if (StringUtils.hasText(oneToOne.mappedBy())) { + getTargetMappedFields().add(nextMappedField); + } + else { + getSourceMappedFields().add((MappedFieldPerceroObject) nextMappedField); + } + } + Boolean isPropertyField = true; Entity nextEntity = (Entity) nextField.getType().getAnnotation(Entity.class); if (nextEntity != null) { entityFields.add(nextField); - toOneFields.add(nextMappedField); + toOneFields.add( (MappedFieldPerceroObject) nextMappedField ); isPropertyField = false; } @@ -464,7 +521,11 @@ else if (implementsInterface(nextFieldClass, List.class)) if (id == null) id = (Id) nextField.getAnnotation(Id.class); if (id != null) { - uniqueConstraints.add(nextMappedField); + idMappedField = nextMappedField; + + List uniqueConstraintList = new ArrayList(1); + uniqueConstraintList.add(nextMappedField); + uniqueConstraints.add(uniqueConstraintList); // Check to see if this class has a Generated ID. GeneratedValue generatedValue = (GeneratedValue) nextField.getAnnotation(GeneratedValue.class); @@ -475,14 +536,26 @@ else if (implementsInterface(nextFieldClass, List.class)) if (column == null) column = (Column) nextField.getAnnotation(Column.class); if (column != null) { - if (column.unique()) - uniqueConstraints.add(nextMappedField); + if (column.unique()) { + List uniqueConstraintList = new ArrayList(1); + uniqueConstraintList.add(nextMappedField); + uniqueConstraints.add(uniqueConstraintList); + } if (column.name() != null && column.name().trim().length() > 0) nextMappedField.setColumnName(column.name()); else nextMappedField.setColumnName(nextField.getName()); } + + JoinColumn joinColumn = (JoinColumn) theGetter.getAnnotation(JoinColumn.class); + if (joinColumn == null) + joinColumn = (JoinColumn) nextField.getAnnotation(JoinColumn.class); + if (joinColumn != null) { + if (StringUtils.hasText(joinColumn.name())) { + nextMappedField.setJoinColumnName(joinColumn.name()); + } + } // Get NamedQueries for handling Access Rights. AccessRights accessRights = (AccessRights) nextField.getAnnotation(AccessRights.class); @@ -504,11 +577,18 @@ else if (implementsInterface(nextFieldClass, List.class)) nextMappedField.updateQuery.setQuery(nextAccessRight.query()); } else*/ if (nextAccessRight.type().equalsIgnoreCase("readQuery")) { - if (nextAccessRight.query().indexOf("jpql:") >= 0) + if (nextAccessRight.query().indexOf("jpql:") >= 0) { nextMappedField.setReadQuery(new JpqlQuery()); - else - nextMappedField.setReadQuery(new MappedQuery()); - nextMappedField.getReadQuery().setQuery(nextAccessRight.query()); + nextMappedField.getReadQuery().setQuery(nextAccessRight.query()); + } + else if (nextAccessRight.query().indexOf("sql:") >= 0) { + nextMappedField.setReadQuery(new SqlQuery(nextAccessRight.query().substring(nextAccessRight.query().indexOf("sql:")+4))); + } + else { + // Whatever type of Query this is, it is not supported. + continue; +// nextMappedField.setReadQuery(new MappedQuery()); + } nextMappedField.setHasReadAccessRights(true); readAccessRightsFieldReferences.add(nextMappedField); } /*else if (nextAccessRight.type().equalsIgnoreCase("deleteQuery")) { @@ -521,11 +601,18 @@ else if (implementsInterface(nextFieldClass, List.class)) // Add to queries list. IMappedQuery nextQuery = null; - if (nextAccessRight.query().indexOf("jpql:") >= 0) + if (nextAccessRight.query().indexOf("jpql:") >= 0) { nextQuery = new JpqlQuery(); - else - nextQuery = new MappedQuery(); - nextQuery.setQuery(nextAccessRight.query()); + nextQuery.setQuery(nextAccessRight.query()); + } + else if (nextAccessRight.query().indexOf("sql:") >= 0) { + nextQuery = new SqlQuery(nextAccessRight.query().substring(nextAccessRight.query().indexOf("sql:")+4)); + } + else { + // Unsupported Query type + continue; +// nextQuery = new MappedQuery(); + } nextQuery.setQueryName(nextAccessRight.type()); nextMappedField.queries.add(nextQuery); @@ -623,10 +710,17 @@ public void initializeQueries() { } } + if (!StringUtils.hasText(tableSchema)) { + Table table = (Table) tempClazz.getAnnotation(Table.class); + if (table != null && StringUtils.hasText(table.schema())) { + tableSchema = table.schema(); + } + } + if (!StringUtils.hasText(dataProviderName)) { DataProvider dataProvider = (DataProvider) tempClazz.getAnnotation(DataProvider.class); if (dataProvider != null) { - dataProviderName = dataProvider.name(); + setDataProviderName(dataProvider.name()); } } @@ -658,9 +752,9 @@ public void initializeQueries() { } else if (nextNamedQuery.name().equalsIgnoreCase("readQuery")) { readQuery = QueryFactory.createQuery(nextNamedQuery.query()); - Iterator itrToOneFields = toOneFields.iterator(); + Iterator itrToOneFields = toOneFields.iterator(); while(itrToOneFields.hasNext()) { - MappedField nextMappedField = itrToOneFields.next(); + MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); MappedClass referencedMappedClass = mcm.getMappedClassByClassName(nextMappedField.getField().getType().getCanonicalName()); // Need to find the corresponding field. for(MappedField nextRefMappedField : referencedMappedClass.toManyFields) { @@ -754,6 +848,9 @@ public void initializeRelationships() { oneToMany = (OneToMany) nextMappedField.getField().getAnnotation(OneToMany.class); if (oneToMany != null) { +// // This must be a source MappedField +// sourceMappedFields.add((MappedFieldPerceroObject) nextMappedField); + //toManyFields.add(nextMappedField); ParameterizedType listType = (ParameterizedType) nextMappedField.getField().getGenericType(); Class listClass = (Class) listType.getActualTypeArguments()[0]; @@ -765,16 +862,34 @@ public void initializeRelationships() { nextMappedField.setHasReadAccessRights(true); readAccessRightsFieldReferences.add(nextMappedField); } + } ManyToOne manyToOne = (ManyToOne) nextMappedField.getGetter().getAnnotation(ManyToOne.class); if (manyToOne == null) manyToOne = (ManyToOne) nextMappedField.getField().getAnnotation(ManyToOne.class); +// if (manyToOne != null) { +// // This must be a target MappedField +// targetMappedFields.add(nextMappedField); +// } + OneToOne oneToOne = (OneToOne) nextMappedField.getGetter().getAnnotation(OneToOne.class); if (oneToOne == null) oneToOne = (OneToOne) nextMappedField.getField().getAnnotation(OneToOne.class); +// if (oneToOne != null) { +// // Not sure if this is source or target, let's find out... +// if(StringUtils.hasText(oneToOne.mappedBy())) { +// // This must be a target MappedField +// targetMappedFields.add(nextMappedField); +// } +// else { +// // This must be a source MappedField +// sourceMappedFields.add((MappedFieldPerceroObject) nextMappedField); +// } +// } + if (manyToOne != null && !manyToOne.optional() || oneToOne != null && !oneToOne.optional()) { diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedField.java b/src/main/java/com/percero/agents/sync/metadata/MappedField.java index 7de3f1a..be8e245 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedField.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedField.java @@ -24,6 +24,7 @@ public class MappedField { private Method getter; private Method setter; private String columnName; + private String joinColumnName; private Boolean useLazyLoading = true; public List queries = new ArrayList(); private Boolean hasReadAccessRights = false; @@ -91,6 +92,14 @@ public void setColumnName(String columnName) { this.columnName = columnName; } + public String getJoinColumnName() { + return joinColumnName; + } + + public void setJoinColumnName(String joinColumnName) { + this.joinColumnName = joinColumnName; + } + public Boolean getUseLazyLoading() { return true; // TODO: Lazy Loading is always used. Need better method to NOT use lazy-loading. @@ -161,6 +170,11 @@ public Object getValue(Object anObject) throws IllegalArgumentException, return result; } + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Object value = getValue(anObject); + return (value != null); + } + public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Object valueA = getValue(objectA); diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldBool.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldBool.java index 301a5e2..7cf5b8b 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldBool.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldBool.java @@ -22,6 +22,12 @@ public void writeExternalField(ObjectOutput output, Object anObject) output.writeBoolean(booleanValue); } + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Boolean value = (Boolean) getValue(anObject); + return (value != null); + } + public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { boolean valueA = (Boolean) getValue(objectA); diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldBoolean.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldBoolean.java index 6478fc4..297321c 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldBoolean.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldBoolean.java @@ -22,6 +22,12 @@ public void writeExternalField(ObjectOutput output, Object anObject) output.writeBoolean(booleanValue); } + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Boolean value = (Boolean) getValue(anObject); + return (value != null); + } + public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Boolean valueA = (Boolean) getValue(objectA); diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldDate.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldDate.java index ccbdbb2..0b204cd 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldDate.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldDate.java @@ -21,6 +21,12 @@ public void writeJsonField(JsonObject jsonObject, Object anObject) jsonObject.addProperty(getField().getName(), gson.toJson(timestamp)); } + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Date value = (Date) getValue(anObject); + return (value != null && value.getTime() > 0); + } + public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Date valueA = (Date) getValue(objectA); diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldDouble.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldDouble.java index edf1238..ee1ee8c 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldDouble.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldDouble.java @@ -21,6 +21,12 @@ public void writeExternalField(ObjectOutput output, Object anObject) double doubleValue = ((Double) getGetter().invoke(anObject)).doubleValue(); output.writeDouble(doubleValue); } + + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Double value = (Double) getValue(anObject); + return (value != null && value.doubleValue() != 0.0); + } public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldFloat.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldFloat.java index 6ae626a..07df975 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldFloat.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldFloat.java @@ -22,6 +22,12 @@ public void writeExternalField(ObjectOutput output, Object anObject) output.writeFloat(floatValue); } + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Float value = (Float) getValue(anObject); + return (value != null && value.floatValue() != 0.0); + } + public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Float valueA = (Float) getValue(objectA); diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldInt.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldInt.java index ee2e4c7..e6406f8 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldInt.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldInt.java @@ -34,6 +34,12 @@ public void writeExternalField(ObjectOutput output, Object anObject) output.writeInt(intValue); } + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Integer value = (Integer) getValue(anObject); + return (value != null && value.intValue() != 0); + } + public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Integer valueA = (Integer) getValue(objectA); diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldInteger.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldInteger.java index 4df1320..e80d83d 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldInteger.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldInteger.java @@ -38,6 +38,12 @@ public void writeExternalField(ObjectOutput output, Object anObject) output.writeInt(intValue); } + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Integer value = (Integer) getValue(anObject); + return (value != null && value.intValue() != 0); + } + public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { Integer valueA = (Integer) getValue(objectA); diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldList.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldList.java index caf33cd..27d1587 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldList.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldList.java @@ -44,6 +44,13 @@ public void writeExternalField(ObjectOutput output, Object anObject) output.writeObject(objectArray); } + @SuppressWarnings("rawtypes") + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + List value = (List) getValue(anObject); + return (value != null && !value.isEmpty()); + } + public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { List valueA = (List) getValue(objectA); diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldMap.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldMap.java index f94c3e6..bec6223 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldMap.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldMap.java @@ -27,4 +27,12 @@ public void writeExternalField(ObjectOutput output, Object anObject) Object[] objectArray = DataExternalizer.getClassIDPairArray(mapObject.values()); output.writeObject(objectArray); } + + @SuppressWarnings("rawtypes") + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + Map value = (Map) getValue(anObject); + return (value != null && !value.isEmpty()); + } + } diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldPerceroObject.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldPerceroObject.java index dbe8a74..009aac9 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldPerceroObject.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldPerceroObject.java @@ -17,6 +17,21 @@ public class MappedFieldPerceroObject extends MappedField { private static final Logger log = Logger.getLogger(MappedFieldPerceroObject.class); + private Boolean targetEntity = null; + public Boolean isTargetEntity() { + if (targetEntity == null) { + targetEntity = this.getMappedClass().getTargetMappedFields().contains(this); + } + return targetEntity; + } + + private Boolean sourceEntity = null; + public Boolean isSourceEntity() { + if (sourceEntity == null) { + sourceEntity = this.getMappedClass().getSourceMappedFields().contains(this); + } + return sourceEntity; + } @Override public void writeJsonField(JsonObject jsonObject, Object anObject) @@ -68,10 +83,21 @@ public void writeExternalField(ObjectOutput output, Object anObject) output.writeObject(classIdPair); } + public IPerceroObject getPerceroObjectValue(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + IPerceroObject result = (IPerceroObject) getValue(anObject); + return result; + } + + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + IPerceroObject value = getPerceroObjectValue(anObject); + return (value != null && StringUtils.hasText(value.getID())); + } + public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { - IPerceroObject valueA = (IPerceroObject) getValue(objectA); - IPerceroObject valueB = (IPerceroObject) getValue(objectB); + IPerceroObject valueA = getPerceroObjectValue(objectA); + IPerceroObject valueB = getPerceroObjectValue(objectB); if (valueA == null && valueB == null) return true; diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedFieldString.java b/src/main/java/com/percero/agents/sync/metadata/MappedFieldString.java index beefa4f..31370af 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldString.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldString.java @@ -5,6 +5,8 @@ import java.io.ObjectOutput; import java.lang.reflect.InvocationTargetException; +import org.springframework.util.StringUtils; + import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -37,6 +39,12 @@ public void writeExternalField(ObjectOutput output, Object anObject) output.writeUTF(stringValue); } + @Override + public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + String value = (String) getValue(anObject); + return StringUtils.hasText(value); + } + public Boolean compareObjects(Object objectA, Object objectB) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { String valueA = (String) getValue(objectA); diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java b/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java index a303d51..fc18896 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java @@ -7,19 +7,13 @@ import java.util.Map; import org.apache.log4j.Logger; -import org.hibernate.Query; -import org.hibernate.SessionFactory; import org.hibernate.engine.query.NamedParameterDescriptor; import org.hibernate.engine.query.ParamLocationRecognizer; import org.hibernate.engine.query.ParameterMetadata; -import org.hibernate.impl.QueryImpl; -import org.hibernate.impl.SessionFactoryImpl; -import org.hibernate.impl.SessionImpl; import org.hibernate.type.TimestampType; import org.hibernate.type.Type; import org.springframework.util.StringUtils; -import com.percero.agents.sync.services.SyncAgentService; import com.percero.framework.metadata.IMappedQuery; import com.percero.framework.vo.IPerceroObject; @@ -47,10 +41,10 @@ public void setQueryName(String value) { private boolean queryParameterNamesSet = false; private boolean useUserId = false; private boolean useId = false; - private ParameterMetadata parameterMetadata = null; + private boolean useIds = false; @SuppressWarnings("rawtypes") - public boolean getUseId() { + protected void initialize() { if (!queryParameterNamesSet && StringUtils.hasText(query)) { try { @@ -66,6 +60,8 @@ public boolean getUseId() { useUserId = true; else if (nextNamedParameter.equalsIgnoreCase("id")) useId = true; + else if (nextNamedParameter.equalsIgnoreCase("ids")) + useIds = true; } queryParameterNamesSet = true; @@ -73,38 +69,43 @@ else if (nextNamedParameter.equalsIgnoreCase("id")) // Do nothing. } } - + } + + public boolean getUseId() { + initialize(); return this.useId; } - public void setQueryParameters(Query theQuery, Object theObject, String userId) throws Exception { - setQueryParameters(theQuery, theObject, userId, null, null); + public boolean getUseIds() { + initialize(); + return this.useIds; + } + + public String setQueryParameters(String theQuery, Object theObject, String userId) throws Exception { + return setQueryParameters(theQuery, theObject, userId, null); } @SuppressWarnings("rawtypes") - public void setQueryParameters(Query theQuery, Object theObject, String userId, Object[] params, SessionImpl s) throws Exception { + public String setQueryParameters(String theQuery, Object theObject, String userId, Object[] params) throws Exception { if (!queryParameterNamesSet) { - for(String nextNamedParameter : theQuery.getNamedParameters()) { - if (nextNamedParameter.equalsIgnoreCase("userId")) - useUserId = true; - else if (nextNamedParameter.equalsIgnoreCase("id")) - useId = true; - } + useUserId = theQuery.contains(":userId"); + useId = theQuery.contains(":id"); + useIds = theQuery.contains(":ids"); queryParameterNamesSet = true; } if (useId) { if (theObject instanceof String) { try { - theQuery.setString("id", (String)theObject); + theQuery = theQuery.replaceAll(":id", "\"" + (String)theObject + "\""); } catch(Exception e) { log.warn("Unable to set ID for MappedQuery from String"); } } else if (theObject instanceof IPerceroObject) { try { - theQuery.setString("id", ((IPerceroObject)theObject).getID()); + theQuery = theQuery.replaceAll(":id", "\"" + ((IPerceroObject)theObject).getID() + "\""); } catch(Exception e) { log.warn("Unable to set ID for MappedQuery from IPerceroObject"); } @@ -117,7 +118,7 @@ else if (theObject instanceof Object[]) String[] nextParamSplit = ((String) nextParam).split(":"); if (nextParamSplit.length == 2) { if (nextParamSplit[0].equalsIgnoreCase("id")) { - theQuery.setString("id", nextParamSplit[1]); + theQuery = theQuery.replaceAll(":id", "\"" + nextParamSplit[1] + "\""); break; } } @@ -127,7 +128,7 @@ else if (theObject instanceof Object[]) } else if (nextParam instanceof IPerceroObject) { try { - theQuery.setString("id", ((IPerceroObject)nextParam).getID()); + theQuery = theQuery.replaceAll(":id", "\"" + ((IPerceroObject)nextParam).getID() + "\""); } catch(Exception e) { log.warn("Unable to set ID for MappedQuery from IPerceroObject"); } @@ -135,9 +136,87 @@ else if (nextParam instanceof IPerceroObject) { } } } + if (useIds) { + if (theObject instanceof String) { + try { + theQuery = theQuery.replaceAll(":ids", "'" + (String)theObject + "'"); + } catch(Exception e) { + log.warn("Unable to set IDs for MappedQuery from String"); + } + } + else if (theObject instanceof IPerceroObject) { + try { + theQuery = theQuery.replaceAll(":ids", "'" + ((IPerceroObject)theObject).getID() + "'"); + } catch(Exception e) { + log.warn("Unable to set IDs for MappedQuery from IPerceroObject"); + } + } + else if (theObject instanceof Object[]) + { + Object[] theObjectArray = (Object[]) theObject; + + Collection idsList = new HashSet(theObjectArray.length); + + for(Object nextParam : theObjectArray) { + if (nextParam instanceof String) { + try { + String[] nextParamSplit = ((String) nextParam).split(":"); + if (nextParamSplit.length == 2) { + if (nextParamSplit[0].equalsIgnoreCase("id")) { + idsList.add(nextParamSplit[1]); + break; + } + } + } catch(Exception e) { + log.warn("Unable to set IDs for MappedQuery from String"); + } + } + else if (nextParam instanceof IPerceroObject) { + try { + idsList.add(((IPerceroObject)nextParam).getID()); + } catch(Exception e) { + log.warn("Unable to set IDs for MappedQuery from IPerceroObject"); + } + } + } + + theQuery.setParameterList("ids", idsList); + } + else if (theObject instanceof Collection) + { + Collection theObjectCollection = (Collection) theObject; + + Collection idsList = new HashSet(theObjectCollection.size()); + + for(Object nextParam : theObjectCollection) { + if (nextParam instanceof String) { + try { + String[] nextParamSplit = ((String) nextParam).split(":"); + if (nextParamSplit.length == 2) { + if (nextParamSplit[0].equalsIgnoreCase("id")) { + idsList.add(nextParamSplit[1]); + break; + } + } + } catch(Exception e) { + log.warn("Unable to set IDs for MappedQuery from String"); + } + } + else if (nextParam instanceof IPerceroObject) { + try { + idsList.add(((IPerceroObject)nextParam).getID()); + } catch(Exception e) { + log.warn("Unable to set IDs for MappedQuery from IPerceroObject"); + } + } + } + + theQuery.setParameterList("ids", idsList); + } + } if (useUserId) { try { - theQuery.setString("userId", userId); + theQuery = theQuery.replaceAll(":userId", "\"" + userId + "\""); } catch(Exception e) { log.warn("Unable to set UserID for MappedQuery"); } @@ -145,13 +224,13 @@ else if (nextParam instanceof IPerceroObject) { // Get Parameter MetaData. if (params != null && params.length > 0) { - if (parameterMetadata == null) { - try { - parameterMetadata = ((SessionFactoryImpl)s.getSessionFactory()).getQueryPlanCache().getHQLQueryPlan(theQuery.getQueryString(), false, (s).getEnabledFilters()).getParameterMetadata(); - } catch(Exception e) { - log.warn("Unable to get ParameterMetaData from Query:\n" + theQuery.getQueryString(), e); - } - } +// if (parameterMetadata == null) { +// try { +// parameterMetadata = ((SessionFactoryImpl)s.getSessionFactory()).getQueryPlanCache().getHQLQueryPlan(theQuery.getQueryString(), false, (s).getEnabledFilters()).getParameterMetadata(); +// } catch(Exception e) { +// log.warn("Unable to get ParameterMetaData from Query:\n" + theQuery.getQueryString(), e); +// } +// } for(Object nextParam : params) { if (nextParam instanceof Map) { @@ -173,9 +252,9 @@ else if (nextParam instanceof IPerceroObject) { if (expectedType instanceof TimestampType) { Date dateValue = new Date((Long)value); - theQuery.setDate(strKey, dateValue); + theQuery = theQuery.replaceAll(":" + strKey, "'" + dateValue + "'"); } else { - theQuery.setParameter((String) key, value); + theQuery = theQuery.replaceAll(":" + (String) key, "\"" + value + "\""); } paramSet = true; } @@ -183,7 +262,7 @@ else if (nextParam instanceof IPerceroObject) { // Last ditch effort to set this parameter. if (!paramSet) - theQuery.setParameter((String) key, value); + theQuery = theQuery.replaceAll(":" + (String) key, "\"" + value + "\""); } } catch(Exception e) { log.warn("Unable to apply parameter to filter", e); @@ -195,12 +274,14 @@ else if (nextParam instanceof IPerceroObject) { String[] paramSplit = nextStringParam.split(":"); String key = paramSplit[0]; String value = paramSplit[1]; - theQuery.setParameter(key, value); + theQuery = theQuery.replaceAll(":" + key, "\"" + value + "\""); } catch(Exception e) { log.warn("Unable to apply parameter to filter", e); } } } } + + return theQuery; } } diff --git a/src/main/java/com/percero/agents/sync/metadata/QueryFactory.java b/src/main/java/com/percero/agents/sync/metadata/QueryFactory.java index 87a64e5..2a5afeb 100644 --- a/src/main/java/com/percero/agents/sync/metadata/QueryFactory.java +++ b/src/main/java/com/percero/agents/sync/metadata/QueryFactory.java @@ -5,12 +5,18 @@ public class QueryFactory { public static IMappedQuery createQuery(String query){ IMappedQuery result = null; - if (query.indexOf("jpql:") >= 0) + if (query.indexOf("jpql:") >= 0) { result = new JpqlQuery(); - else - result = new MappedQuery(); + result.setQuery(query); + } + else if (query.indexOf("sql:") >= 0) { + result = new SqlQuery(query.substring(query.indexOf("sql:")+4)); + } + else { + // Unsupported Query type + return null; + } - result.setQuery(query); return result; } } diff --git a/src/main/java/com/percero/agents/sync/metadata/SqlQuery.java b/src/main/java/com/percero/agents/sync/metadata/SqlQuery.java index 463991b..25ee7a4 100644 --- a/src/main/java/com/percero/agents/sync/metadata/SqlQuery.java +++ b/src/main/java/com/percero/agents/sync/metadata/SqlQuery.java @@ -1,8 +1,46 @@ package com.percero.agents.sync.metadata; +import org.apache.log4j.Logger; +import org.hibernate.Query; +import org.hibernate.engine.query.ParameterMetadata; +import org.hibernate.impl.SessionFactoryImpl; +import org.hibernate.impl.SessionImpl; + public class SqlQuery extends MappedQuery { + private static final Logger log = Logger.getLogger(SqlQuery.class); + public SqlQuery(String query){ + super(); super.setQuery(query); } + + public SqlQuery(){ + super(); + } + + @Override + protected ParameterMetadata fetchParameterMetadataFromQuery(Query theQuery, SessionImpl s) { + ParameterMetadata parameterMetadata = null; + + try { + // TODO: This needs to be NativeSQL specific +// parameterMetadata = ((SessionFactoryImpl)s.getSessionFactory()).getQueryPlanCache().getNativeSQLQueryPlan(theQuery.getQueryString(), false, s.getEnabledFilters()).getParameterMetadata(); + + parameterMetadata = ((SessionFactoryImpl)s.getSessionFactory()).getQueryPlanCache().getHQLQueryPlan(theQuery.getQueryString(), false, s.getEnabledFilters()).getParameterMetadata(); + } catch(Exception e) { + log.warn("Unable to get ParameterMetaData from Query:\n" + theQuery.getQueryString(), e); + } + + return parameterMetadata; + } + + @Override + public Query createQuery(Object theObject, String userId, Object[] params, + SessionImpl s) throws Exception { + Query theQuery = s.createSQLQuery(getQuery()); + setQueryParameters(theQuery, theObject, userId, params, s); + + return theQuery; + } } diff --git a/src/main/java/com/percero/agents/sync/services/DAODataProvider.java b/src/main/java/com/percero/agents/sync/services/DAODataProvider.java new file mode 100644 index 0000000..249d3ef --- /dev/null +++ b/src/main/java/com/percero/agents/sync/services/DAODataProvider.java @@ -0,0 +1,2048 @@ +package com.percero.agents.sync.services; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtField; +import javassist.CtMethod; + +import org.apache.log4j.Logger; +import org.codehaus.jackson.map.ObjectMapper; +import org.hibernate.PropertyValueException; +import org.hibernate.Query; +import org.hibernate.QueryException; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.impl.SessionImpl; +import org.hibernate.type.Type; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import com.percero.agents.sync.access.RedisKeyUtils; +import com.percero.agents.sync.dao.IDataAccessObject; +import com.percero.agents.sync.datastore.ICacheDataStore; +import com.percero.agents.sync.exceptions.SyncDataException; +import com.percero.agents.sync.exceptions.SyncException; +import com.percero.agents.sync.hibernate.SyncHibernateUtils; +import com.percero.agents.sync.metadata.IMappedClassManager; +import com.percero.agents.sync.metadata.JpqlQuery; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClassManagerFactory; +import com.percero.agents.sync.metadata.MappedField; +import com.percero.agents.sync.metadata.MappedFieldList; +import com.percero.agents.sync.metadata.MappedFieldPerceroObject; +import com.percero.agents.sync.metadata.MappedFieldString; +import com.percero.agents.sync.metadata.SqlQuery; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.agents.sync.vo.ClassIDPair; +import com.percero.agents.sync.vo.ClassIDPairs; +import com.percero.agents.sync.vo.IJsonObject; +import com.percero.framework.metadata.IMappedQuery; +import com.percero.framework.vo.IPerceroObject; +import com.percero.framework.vo.PerceroList; + +@Component +public class DAODataProvider implements IDataProvider { + + // TODO: Better manage Hibernate Sessions (opening and closing). + + private static final Logger log = Logger.getLogger(DAODataProvider.class); + + public void initialize() + { + // Do nothing. + } + + public String getName() { + return "syncAgent"; + } + + @Autowired + IDataProviderManager dataProviderManager; + public void setDataProviderManager(IDataProviderManager value) { + dataProviderManager = value; + } + + @Autowired + DAORegistry daoRegistry; + public void setDaoRegistry(DAORegistry value) { + daoRegistry = value; + } + + @Autowired + ICacheDataStore cacheDataStore; + + @Autowired + Long cacheTimeout = Long.valueOf(60 * 60 * 24 * 14); // Two weeks + + @Autowired + ObjectMapper safeObjectMapper; + + + + @SuppressWarnings({ "rawtypes", "unchecked" }) + // TODO: @Transactional(readOnly=true) + public PerceroList getAllByName(String className, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception { + IDataAccessObject dao = daoRegistry.getDataAccessObject(className); + return PerceroList result = dao.getAll(pageNumber, pageSize, returnTotal, userId); + } + + @SuppressWarnings({ "rawtypes" }) + // TODO: @Transactional(readOnly=true) + public Integer countAllByName(String aClassName, String userId) throws Exception { + Session s = appSessionFactory.openSession(); + try { + Query countQuery = null; + Class theClass = MappedClass.forName(aClassName); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); + boolean isValidReadQuery = false; + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { + isValidReadQuery = true; + } + } + + if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ + if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ + throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); + } + + String selectQueryString = mappedClass.getReadAllQuery().getQuery(); + + String countQueryString = "select count(*) from ("+selectQueryString+") as U"; + + countQuery = s.createSQLQuery(countQueryString); + countQuery.setParameter("userId", userId); + } + else if (theClass != null) { + String countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; + + // If the Read Query/Filter uses the ID, then we need to check against each ID here. + if (isValidReadQuery) { + String queryFilterString = mappedClass.getReadQuery().getQuery(); + if (mappedClass.getReadQuery().getUseId()) { + // Need to replace :id with + queryFilterString = queryFilterString.replaceAll(":id", "getAllResult.ID"); + queryFilterString = queryFilterString.replaceAll(":Id", "getAllResult.ID"); + queryFilterString = queryFilterString.replaceAll(":iD", "getAllResult.ID"); + queryFilterString = queryFilterString.replaceAll(":ID", "getAllResult.ID"); + } + String countQueryFilterString = queryFilterString; + countQueryFilterString = countQueryString + " WHERE (" + countQueryFilterString + ") > 0"; + + countQuery = s.createQuery(countQueryFilterString); + mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); + } + else { + countQueryString += " ORDER BY ID"; + countQuery = s.createQuery(countQueryString); + } + } + + if (countQuery != null) { +// log.debug(countQuery.toString()); + Integer result = ((Number)countQuery.uniqueResult()).intValue(); + return result; + } + else { + return null; + } + + } catch (Exception e) { + log.error("Unable to countAllByName", e); + } finally { + s.close(); + } + + return 0; + } + + public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String userId) { + Session s = appSessionFactory.openSession(); + try { + if (mappedClass != null) { + for(IMappedQuery nextQuery : mappedClass.queries) + { + if (queryName.equalsIgnoreCase(nextQuery.getQueryName())) + { + Query readFilter = s.createQuery(nextQuery.getQuery()); + nextQuery.setQueryParameters(readFilter, queryArguments, userId, queryArguments, (SessionImpl)s); + return processQueryResults(mappedClass.className + "_" + queryName, readFilter, readFilter.list()); + } + } + } + } catch (Exception e) { + log.error("Unable to runQuery", e); + } finally { + if (s != null && s.isOpen()) + s.close(); + } + + return null; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected static List processQueryResults(String resultClassName, Query updateFilter, List updateFilterResult) throws Exception { + String[] returnAliases = updateFilter.getReturnAliases(); + Type[] returnTypes = updateFilter.getReturnTypes(); + + String[] fieldNames = new String[returnAliases.length]; + String[] getMethodNames = new String[returnAliases.length]; + String[] setMethodNames = new String[returnAliases.length]; + Class[] fieldClasses = new Class[returnAliases.length]; + + Class clazz = null; + ClassPool pool = null; + CtClass evalClass = null; + + if (returnAliases.length > 1) { + try { + clazz = MappedClass.forName(resultClassName); + } catch(Exception e) { + // Class must not yet exist, so let's create it. + } + + if (clazz == null) { + pool = ClassPool.getDefault(); + evalClass = pool.makeClass(resultClassName); + } + + // Create a new Class based on the result set. + for(int i = 0; i < returnAliases.length; i++) { + Type nextType = returnTypes[i]; + String nextTypeCanonicalName = nextType.getReturnedClass().getCanonicalName(); + String nextFieldName = returnAliases[i]; + try { + Integer.parseInt(nextFieldName); + nextFieldName = "field" + i; + } catch(NumberFormatException nfe) { + // Do nothing. Simply means the field name is not a Number. + } + String nextUpperFieldName = nextFieldName.substring(0, 1).toUpperCase() + nextFieldName.substring(1); + + fieldNames[i] = nextFieldName; + getMethodNames[i] = "get" + nextUpperFieldName; + setMethodNames[i] = "set" + nextUpperFieldName; + fieldClasses[i] = nextType.getReturnedClass(); + + if (evalClass != null) { + evalClass.addField(CtField.make("private " + fieldClasses[i].getCanonicalName() + " " + nextFieldName + ";", evalClass)); + evalClass.addMethod(CtMethod.make("public void " + setMethodNames[i] + "(" + fieldClasses[i].getCanonicalName() + " value) {this." + nextFieldName + " = value;}", evalClass)); + evalClass.addMethod(CtMethod.make("public " + nextTypeCanonicalName +" " + getMethodNames[i] + "() {return this." + nextFieldName + ";}", evalClass)); + } + } + + if (clazz == null && evalClass != null) { + clazz = evalClass.toClass(); + } + } + + List results = new ArrayList(); + + // Now populate the newly created objects. + for(Object nextResult : (List)updateFilterResult) { + + if (nextResult instanceof Object[]) { + Object nextObject = clazz.newInstance(); + for(int i = 0; i < returnAliases.length; i++) { + Class[] formalParams = new Class[] { fieldClasses[i] }; + Method setMethod = clazz.getDeclaredMethod(setMethodNames[i], formalParams); + setMethod.invoke(nextObject, ((Object[])nextResult)[i]); + } + + results.add(nextObject); + } else + results.add(nextResult); + } + + return results; + } + + //@SuppressWarnings({ "rawtypes", "unchecked" }) + public IPerceroObject findById(ClassIDPair classIdPair, String userId) { + boolean hasReadQuery = false; + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { + hasReadQuery = true; + } + } + + Session s = null; + try { + boolean hasAccess = true; + IPerceroObject result = systemGetById(classIdPair); + + if (result != null) { + if (hasReadQuery) { + if (s == null) + s = appSessionFactory.openSession(); + Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); + mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); + Number readFilterResult = (Number) readFilter.uniqueResult(); + if (readFilterResult == null || readFilterResult.intValue() <= 0) + hasAccess = false; + } + + if (hasAccess) { + if (s == null) + s = appSessionFactory.openSession(); +// ((BaseDataObject)result).setIsClean(false); + result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s, userId); + return result; + } + else { + return null; + } + } + else { + return null; + } + } catch (Exception e) { + log.error("Unable to findById", e); + } finally { + if (s != null && s.isOpen()) + s.close(); + } + return null; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public IPerceroObject systemGetById(ClassIDPair classIdPair) { + Session s = null; + try { + Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); + + if (theClass != null) { + IPerceroObject result = retrieveFromRedisCache(classIdPair); + String key = null; + + if (result == null) { + + result = readObjectFromDatabase(classIdPair, false); + populateToManyRelationships(result, true, null); + populateToOneRelationships(result, true, null); + /** + * CRB: Going direct to database instead. + s = appSessionFactory.openSession(); + result = (IPerceroObject) s.get(theClass, classIdPair.getID()); + */ + + // Now put the object in the cache. + if (result != null) { + key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); +// result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); + if (cacheTimeout > 0) + cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); + } + else { + // Not necessarily a problem but could be helpful when debugging. + log.debug("Unable to retrieve object from database: " + classIdPair.toJson()); + } + } + else { + key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); + } + + // (Re)Set the expiration. + if (cacheTimeout > 0 && key != null) { + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + } + + return result; + } else { + return null; + } + } catch (Exception e) { + log.error("Unable to systemGetById: "+classIdPair.toJson(), e); + } finally { + if (s != null && s.isOpen()) + s.close(); + } + return null; + } + +// @SuppressWarnings({ "rawtypes" }) +// public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, Class theClass, Session s) { +// Boolean sessionAlreadyOpen = false; +// try { +// if (theClass != null) { +// IPerceroObject result = retrieveFromRedisCache(classIdPair); +// String key = null; +// +// if (result == null) { +// if (s == null || !s.isOpen()) { +// s = appSessionFactory.openSession(); +// } +// else { +// sessionAlreadyOpen = true; +// } +// result = (IPerceroObject) s.get(theClass, classIdPair.getID()); +// +// // Now put the object in the cache. +// if (result != null) { +// key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); +// result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); +// if (cacheTimeout > 0) +// redisDataStore.setValue(key, ((BaseDataObject)result).toJson()); +// } +// else { +// log.warn("Unable to retrieve object from database: " + classIdPair.toString()); +// } +// } +// else { +// key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); +// } +// +// // (Re)Set the expiration. +// if (cacheTimeout > 0 && key != null) { +// redisDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); +// } +// +// return result; +// } else { +// return null; +// } +// } catch (Exception e) { +// log.error("Unable to systemGetById: "+classIdPair.toJson(), e); +// } finally { +// // Only close the session if it wasn't already open. +// if (!sessionAlreadyOpen) { +// if (s != null && s.isOpen()) { +// s.close(); +// } +// } +// } +// return null; +// } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Exception { + IPerceroObject result = null; + if (cacheTimeout > 0) { + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + Class theClass = MappedClass.forName(classIdPair.getClassName()); + MappedClass mc = mcm.getMappedClassByClassName(classIdPair.getClassName()); + + String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); + String jsonObjectString = (String) cacheDataStore.getValue(key); + if (jsonObjectString != null) { + if (IJsonObject.class.isAssignableFrom(theClass)) { + IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); + jsonObject.fromJson(jsonObjectString); + result = (IPerceroObject) jsonObject; + } + else { + result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); + } + } + else { + // Check MappedClass' child classes. + Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); + while (itrChildMappedClasses.hasNext()) { + MappedClass nextChildMc = itrChildMappedClasses.next(); + key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); + jsonObjectString = (String) cacheDataStore.getValue(key); + if (jsonObjectString != null) { + result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); + return result; + } + } + } + } + + return result; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Map retrieveFromRedisCache(ClassIDPairs classIdPairs, Boolean pleaseSetTimeout) throws Exception { + Map result = new HashMap(classIdPairs.getIds().size()); + + if (cacheTimeout > 0) { + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + Class theClass = MappedClass.forName(classIdPairs.getClassName()); + MappedClass mc = mcm.getMappedClassByClassName(classIdPairs.getClassName()); + + Set keys = new HashSet(classIdPairs.getIds().size()); + Iterator itrIds = classIdPairs.getIds().iterator(); + while (itrIds.hasNext()) { + String nextId = itrIds.next(); + String nextKey = RedisKeyUtils.classIdPair(classIdPairs.getClassName(), nextId); + keys.add(nextKey); + + // Check MappedClass' child classes. + Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); + while (itrChildMappedClasses.hasNext()) { + MappedClass nextChildMc = itrChildMappedClasses.next(); + if (nextChildMc.clazz == BaseDataObject.class) { + // Reached the top level, so break. + break; + } + nextKey = RedisKeyUtils.classIdPair(nextChildMc.className, nextId); + keys.add(nextKey); + } + } + +// String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); + List jsonObjectStrings = cacheDataStore.getValues(keys); + Iterator itrJsonObjectStrings = jsonObjectStrings.iterator(); + while (itrJsonObjectStrings.hasNext()) { + String jsonObjectString = (String) itrJsonObjectStrings.next(); + if (jsonObjectString != null) { + if (IJsonObject.class.isAssignableFrom(theClass)) { + IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); + jsonObject.fromJson(jsonObjectString); + result.put( (((IPerceroObject) jsonObject).getID()), (IPerceroObject) jsonObject ); + } + else { + IPerceroObject nextPerceroObject = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); + result.put( nextPerceroObject.getID(), nextPerceroObject); + } + + } +// else { +// // Check MappedClass' child classes. +// Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); +// while (itrChildMappedClasses.hasNext()) { +// MappedClass nextChildMc = itrChildMappedClasses.next(); +// key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); +// jsonObjectString = (String) redisDataStore.getValue(key); +// if (jsonObjectString != null) { +// result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); +// return result; +// } +// } +// } + } + + if (pleaseSetTimeout) { + cacheDataStore.expire(keys, cacheTimeout, TimeUnit.SECONDS); + } + } + + return result; + } + + @SuppressWarnings({ "rawtypes" }) + public Boolean getReadAccess(ClassIDPair classIdPair, String userId) { + Session s = appSessionFactory.openSession(); + try { + Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); + + if (theClass != null) { + IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); + + boolean hasAccess = (parent != null); + + if (hasAccess) { + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ + Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); + mappedClass.getReadQuery().setQueryParameters(readFilter, parent, userId); + Number readFilterResult = (Number) readFilter.uniqueResult(); + if (readFilterResult == null || readFilterResult.intValue() <= 0) + hasAccess = false; + } + } + } + + return hasAccess; + } + } catch (Exception e) { + log.error("Unable to getReadAccess", e); + } finally { + s.close(); + } + return false; + } + + @SuppressWarnings({ "rawtypes" }) + public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { + Session s = appSessionFactory.openSession(); + try { + Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); + + if (theClass != null) { + IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); + + if (parent == null) + return true; + + boolean hasAccess = true; + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); + if (mappedClass != null) { + if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ + Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); + mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, parent, userId); + Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); + if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) + hasAccess = false; + } + } + + return hasAccess; + } + } catch (Exception e) { + log.error("Unable to getDeleteAccess", e); + } finally { + s.close(); + } + return false; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public List findByIds(ClassIDPairs classIdPairs, String userId) { + List result = null; + + boolean hasAccess = true; + Class theClass = null; + try { + theClass = MappedClass.forName(classIdPairs.getClassName()); + } catch (ClassNotFoundException e2) { + log.error("Unable to get Class from class name " + classIdPairs.getClassName(), e2); + return result; + } + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPairs.getClassName()); + boolean isValidReadQuery = false; + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { + isValidReadQuery = true; + } + + } + + if (hasAccess) { + if (theClass != null) { + Set idsSet = new HashSet(classIdPairs.getIds().size()); + idsSet.addAll(classIdPairs.getIds()); + + try { + // Attempt to get as many from the cache as possible... + Map cachedObjects = retrieveFromRedisCache(classIdPairs, true); + + if (!cachedObjects.isEmpty()) { + result = new ArrayList(cachedObjects.size()); + List cachedResults = new ArrayList(cachedObjects.size()); + cachedResults.addAll(cachedObjects.values()); + idsSet.removeAll(cachedObjects.keySet()); + + // If there is a read query, we need to check each object through that query. + if (isValidReadQuery) { + Session s = null; + try { + // Need to clean each result for the user. + // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function + s = appSessionFactory.openSession(); + + Iterator itrCachedResults = cachedResults.iterator(); + while (itrCachedResults.hasNext()) { + IPerceroObject nextCachedResult = itrCachedResults.next(); + if (isValidReadQuery) { + Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); + mappedClass.getReadQuery().setQueryParameters(readFilter, nextCachedResult, userId); + Number readFilterResult = (Number) readFilter.uniqueResult(); + if (readFilterResult == null || readFilterResult.intValue() <= 0) + hasAccess = false; + } + + if (hasAccess) { + result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); + } + } + } catch (Exception e) { + log.error("Error cleaning object for user in findByIds", e); + } finally { + if (s != null && s.isOpen()) { + s.close(); + } + } + } + else { + // This class has relationship objects that need to be cleaned. + if (!mappedClass.getReadAccessRightsFieldReferences().isEmpty()) { + Session s = null; + try { + // Need to clean each result for the user. + // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function + // TODO: Maybe only clean relationships that are in mappedClass.readAccessRightsFieldReferences? + s = appSessionFactory.openSession(); + + Iterator itrCachedResults = cachedResults.iterator(); + while (itrCachedResults.hasNext()) { + IPerceroObject nextCachedResult = itrCachedResults.next(); + result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); + } + } catch (Exception e) { + log.error("Error cleaning object for user in findByIds", e); + } finally { + if (s != null && s.isOpen()) { + s.close(); + } + } + } + else { + // This class has NO read access query AND has NO relationships that require cleaning, + // since this object is completely retrieved from redis, we can send as-is. + // Though this may seem rare, this is probably a very common path. + result.addAll(cachedResults); + } + } + } + } catch (Exception e1) { + // We errored out here, but we can still try and retrieve from the database. + log.error("Error retrieving objects from redis cache, attempting to retrieve from database", e1); + } + + // Now get the rest from the database. + if (!idsSet.isEmpty()) { + + + /** + * CRB: Going direct to database instead of Hibernate + String queryString = "SELECT findByIdsResult FROM " + classIdPairs.getClassName() + " findByIdsResult WHERE findByIdsResult.ID IN (:idsSet)"; + */ + + // Open the database session. + Session s = null; + try { + s = appSessionFactory.openSession(); + /** + * CRB: Going direct to database instead of Hibernate + Query query = null; + + // If the Read Query/Filter uses the ID, then we need to check against each ID here. + if (isValidReadQuery) { + String queryFilterString = mappedClass.getReadQuery().getQuery(); + if (mappedClass.getReadQuery().getUseId()) { + // Need to replace :id with + queryFilterString = queryFilterString.replaceAll(":id", "findByIdsResult.ID"); + queryFilterString = queryFilterString.replaceAll(":Id", "findByIdsResult.ID"); + queryFilterString = queryFilterString.replaceAll(":iD", "findByIdsResult.ID"); + queryFilterString = queryFilterString.replaceAll(":ID", "findByIdsResult.ID"); + } + queryFilterString = queryString + " AND (" + queryFilterString + ") > 0"; + + query = s.createQuery(queryFilterString); + mappedClass.getReadQuery().setQueryParameters(query, null, userId); + } + else { + query = s.createQuery(queryString); + } + + query.setParameterList("idsSet", idsSet); + List queryResult = query.list(); + */ + List queryResult = readObjectsFromDatabase(classIdPairs, userId); + + for(IPerceroObject nextResult : queryResult) { + populateToManyRelationships(nextResult, true, userId); + populateToOneRelationships(nextResult, true, userId); + } + List cleanedDatabaseObjects = queryResult; + // +// List cleanedDatabaseObjects = (List) SyncHibernateUtils.cleanObject(queryResult, s); + + // Need to put results into cache. + if (cacheTimeout > 0) { + Map mapJsonObjectStrings = new HashMap(cleanedDatabaseObjects.size()); + Iterator itrDatabaseObjects = cleanedDatabaseObjects.iterator(); + while (itrDatabaseObjects.hasNext()) { + IPerceroObject nextDatabaseObject = itrDatabaseObjects.next(); + String nextCacheKey = RedisKeyUtils.classIdPair(nextDatabaseObject.getClass().getCanonicalName(), nextDatabaseObject.getID()); + + mapJsonObjectStrings.put(nextCacheKey, ((BaseDataObject)nextDatabaseObject).toJson()); + } + + // Store the objects in redis. + cacheDataStore.setValues(mapJsonObjectStrings); + // (Re)Set the expiration. + cacheDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); + } + + // Clean the objects for the selected User. + cleanedDatabaseObjects = (List) SyncHibernateUtils.cleanObject(cleanedDatabaseObjects, s, userId); + if (result == null) { + result = cleanedDatabaseObjects; + } + else { + result.addAll(cleanedDatabaseObjects); + } + } catch (QueryException qe) { + log.error("Unable to findByIds", qe); + } catch (Exception e) { + log.error("Unable to findByIds", e); + } finally { + if (s != null && s.isOpen()) { + s.close(); + } + } + } + } + } + + return result; + } + + /** + * CRB: This is the same as findByExample, filtering out the first result. + @SuppressWarnings({ "rawtypes", }) + public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId) throws SyncException { + + MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(theQueryObject.getClass().getCanonicalName()); + if (mappedClass == null) { + log.warn("Missing MappedClass for " + theQueryObject.getClass().getCanonicalName()); + throw new SyncException(SyncException.MISSING_MAPPED_CLASS_ERROR, SyncException.MISSING_MAPPED_CLASS_ERROR_CODE ); + } + + Session s = appSessionFactory.openSession(); + try { + Class objectClass = theQueryObject.getClass(); + + Iterator> itr = mappedClass.uniqueConstraints.iterator(); + while(itr.hasNext()) { + Criteria criteria = null; + List nextConstraint = itr.next(); + +// if (nextConstraint instanceof MappedField) { +// MappedField nextConstraintField = (MappedField) nextConstraint; +// Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); +// if (nextConstraintFieldValue != null) { +// if (criteria == null) +// criteria = s.createCriteria(objectClass); +// Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); +// criteria.add(uniqueFieldValue); +// } +// } +// else if (nextConstraint instanceof List) { + + List listMappedFields = (List) nextConstraint; + Iterator itrMappedFields = listMappedFields.iterator(); + while(itrMappedFields.hasNext()) { + MappedField nextConstraintField = itrMappedFields.next(); + + if (nextConstraintField.isValueSetForQuery(theQueryObject)) { + + } + + Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); + if (nextConstraintFieldValue != null) { + if (criteria == null) + criteria = s.createCriteria(objectClass); + Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); + criteria.add(uniqueFieldValue); + } + } + + if (criteria != null) { + criteria.setMaxResults(1); + Object result = criteria.uniqueResult(); + if (result != null) { + // Make sure user has access. + boolean hasAccess = true; + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ + Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); + mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); + Number readFilterResult = (Number) readFilter.uniqueResult(); + if (readFilterResult == null || readFilterResult.intValue() <= 0) + hasAccess = false; + } + } + + if (hasAccess) { + result = SyncHibernateUtils.cleanObject(result, s, userId); + return (IPerceroObject) result; + } + } + } + } + } catch (Exception e) { + log.error("Unable to findUnique", e); + } finally { + s.close(); + } + + return null; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public IPerceroObject findUnique_OLD(IPerceroObject theQueryObject, String userId) { + Session s = appSessionFactory.openSession(); + try { + Class objectClass = theQueryObject.getClass(); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(objectClass.getName()); + if (mappedClass != null) { + Iterator itr = mappedClass.uniqueConstraints.iterator(); + while(itr.hasNext()) { + Criteria criteria = null; + Object nextConstraint = itr.next(); + if (nextConstraint instanceof MappedField) { + MappedField nextConstraintField = (MappedField) nextConstraint; + Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); + if (nextConstraintFieldValue != null) { + if (criteria == null) + criteria = s.createCriteria(objectClass); + Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); + criteria.add(uniqueFieldValue); + } + } + else if (nextConstraint instanceof List) { + List listMappedFields = (List) nextConstraint; + Iterator itrMappedFields = listMappedFields.iterator(); + while(itrMappedFields.hasNext()) { + MappedField nextConstraintField = itrMappedFields.next(); + Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); + if (nextConstraintFieldValue != null) { + if (criteria == null) + criteria = s.createCriteria(objectClass); + Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); + criteria.add(uniqueFieldValue); + } + } + } + + if (criteria != null) { + criteria.setMaxResults(1); + Object result = criteria.uniqueResult(); + if (result != null) { + // Make sure user has access. + boolean hasAccess = true; + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ + Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); + mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); + Number readFilterResult = (Number) readFilter.uniqueResult(); + if (readFilterResult == null || readFilterResult.intValue() <= 0) + hasAccess = false; + } + } + + if (hasAccess) { + result = SyncHibernateUtils.cleanObject(result, s, userId); + return (IPerceroObject) result; + } + } + } + } + } + } catch (Exception e) { + log.error("Unable to findUnique", e); + } finally { + s.close(); + } + + return null; + } + */ + + // TODO: Add permissions check. + @SuppressWarnings("unchecked") + public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId) throws SyncException { + List result = systemFindByExample(theQueryObject, excludeProperties); + if (result != null) { + // Make sure user has access. + boolean hasAccess = true; + + MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(theQueryObject.getClass().getCanonicalName()); + Session s = appSessionFactory.openSession(); + try { + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ + Query readFilter = mappedClass.getReadQuery().createQuery(result, userId, null, (SessionImpl)s); +// Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); +// mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); + Number readFilterResult = (Number) readFilter.uniqueResult(); + if (readFilterResult == null || readFilterResult.intValue() <= 0) { + hasAccess = false; + } + } + } + + if (hasAccess) { + result = (List) SyncHibernateUtils.cleanObject(result, s, userId); + } + } catch (Exception e) { + log.error("Unable to findByExample", e); + throw new SyncDataException(e); + } finally { + s.close(); + } + } + + return result; + +// Session s = appSessionFactory.openSession(); +// try { +// Criteria criteria = s.createCriteria(theQueryObject.getClass()); +// AssociationExample example = AssociationExample.create(theQueryObject); +// BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); +// example.setPropertySelector(propertySelector); +// criteria.add(example); +// +// List result = criteria.list(); +// result = (List) SyncHibernateUtils.cleanObject(result, s, userId); +// +// return (List) result; +// } catch (Exception e) { +// log.error("Unable to findByExample", e); +// } finally { +// s.close(); +// } +// +// return null; + } + + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public List systemFindByExample(IPerceroObject theQueryObject, List excludeProperties) throws SyncException { + // TODO: Use StringBuilder or something more efficient here. + + List result = new ArrayList(); + + MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(theQueryObject.getClass().getCanonicalName()); + if (mappedClass == null) { + log.warn("Missing MappedClass for " + theQueryObject.getClass().getCanonicalName()); + throw new SyncException(SyncException.MISSING_MAPPED_CLASS_ERROR, SyncException.MISSING_MAPPED_CLASS_ERROR_CODE ); + } + + String selectQueryString = "SELECT "; + String whereString = "WHERE "; + List wherePropertyFields = new ArrayList(); + List whereToOneFields = new ArrayList(); + +// if (excludeProperties == null) { +// excludeProperties = new ArrayList(1); +// } +// if (!excludeProperties.contains(mappedClass.idMappedField)) { +// excludeProperties.add(mappedClass.idMappedField.); +// } + + int selectCounter = 0; + int whereCounter = 0; + + // Iterate over PropertyFields. These are simple fields with their value being stored here. + for(MappedField nextMappedField : mappedClass.propertyFields) { + if (selectCounter > 0) { + selectQueryString += ", "; + } + + selectQueryString += "P." + nextMappedField.getColumnName(); + selectCounter++; + + // Now check the QueryObject to see if this field is a filter. + try { + if (nextMappedField != mappedClass.idMappedField && nextMappedField.isValueSetForQuery(theQueryObject)) { + if (whereCounter > 0) { + whereString += " AND "; + } + if (nextMappedField instanceof MappedFieldString) { + whereString += "P." + nextMappedField.getColumnName() + " LIKE(:" + nextMappedField.getColumnName() + ")"; + } + else { + whereString += "P." + nextMappedField.getColumnName() + "=:" + nextMappedField.getColumnName(); + } + wherePropertyFields.add(nextMappedField); + whereCounter++; + } + } catch (IllegalArgumentException e) { + // Don't necessarily care about this here. + } catch (IllegalAccessException e) { + // Don't necessarily care about this here. + } catch (InvocationTargetException e) { + // Don't necessarily care about this here. + } + } + + // Iterate over ToOneFields, meaning fields where the ID of the relationship is stored on this side of the relationship. + for(MappedFieldPerceroObject nextMappedField : mappedClass.toOneFields) { + + // If this mapped field is the source, then we include it in our query. + if (nextMappedField.isSourceEntity()) { + if (selectCounter > 0) { + selectQueryString += ", "; + } + + selectQueryString += "P." + nextMappedField.getJoinColumnName(); + selectCounter++; + + // Now check the QueryObject to see if this field is a filter. + try { + if (nextMappedField != mappedClass.idMappedField && nextMappedField.isValueSetForQuery(theQueryObject)) { + if (whereCounter > 0) { + whereString += " AND "; + } + whereString += "P." + nextMappedField.getJoinColumnName() + "=:" + nextMappedField.getJoinColumnName(); + whereToOneFields.add(nextMappedField); + whereCounter++; + } + } catch (IllegalArgumentException e) { + // Don't necessarily care about this here. + } catch (IllegalAccessException e) { + // Don't necessarily care about this here. + } catch (InvocationTargetException e) { + // Don't necessarily care about this here. + } + } + else { + System.out.println("No Join Column"); + } + } + + // If there are no Query Fields set, then we simply return an empty list. + if ( (selectCounter + whereCounter) == 0) { + return result; + } + + String fullQueryString = selectQueryString + " FROM " + (StringUtils.hasText(mappedClass.tableSchema) ? mappedClass.tableSchema + "." : "") + mappedClass.tableName + " P " + whereString; + + Session s = appSessionFactory.openSession(); + try { + Query query = s.createSQLQuery(fullQueryString); + + for(MappedField nextMappedField : wherePropertyFields) { + // We know this field has a valid value here. + if (nextMappedField instanceof MappedFieldString) { + query.setParameter(nextMappedField.getColumnName(), "%" + nextMappedField.getValue(theQueryObject) + "%"); + } + else { + query.setParameter(nextMappedField.getColumnName(), nextMappedField.getValue(theQueryObject)); + } + } + for(MappedField nextMappedField : whereToOneFields) { + // Because we know this field has a value set, we know it is an IPerceroObject with valid ID. + query.setParameter(nextMappedField.getJoinColumnName(), ((IPerceroObject) nextMappedField.getValue(theQueryObject)).getID() ); + } + + List queryResult = query.list(); + + Iterator itrQueryResults = queryResult.iterator(); + while (itrQueryResults.hasNext()) { + + IPerceroObject nextPerceroObject = (IPerceroObject) mappedClass.clazz.newInstance(); + + Object[] nextResult = (Object[]) itrQueryResults.next(); + + int j = 0; + for(MappedField nextMappedField : mappedClass.propertyFields) { + Object nextValue = nextResult[j]; + nextMappedField.getSetter().invoke(nextPerceroObject, nextValue); + j++; + } + for(MappedFieldPerceroObject nextMappedField : mappedClass.toOneFields) { + if (nextMappedField.isSourceEntity()) { + Object nextValue = nextResult[j]; + + IPerceroObject nextToOnePerceroObject = (IPerceroObject) nextMappedField.getField().getType().newInstance(); + nextToOnePerceroObject.setID( (String) nextValue ); + + if (!nextMappedField.getUseLazyLoading()) { + IDataProvider dataProvider = nextMappedField.getMappedClass().getDataProvider(); + nextToOnePerceroObject = dataProvider.systemGetById(BaseDataObject.toClassIdPair(nextToOnePerceroObject)); + } + + nextMappedField.getSetter().invoke(nextPerceroObject, nextToOnePerceroObject); + } + } + + nextPerceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(nextPerceroObject, s); + addObjectToCache(nextPerceroObject); + + result.add(nextPerceroObject); + } + } catch(Exception e) { + log.error("Unable to systemFindByExample", e); + // TODO: Throw a SyncException here. + } finally { + s.close(); + } + + // Now clean the results. + result = (List) SyncHibernateUtils.cleanObject(result, s, null); + + return result; + } + + @SuppressWarnings("unchecked") + public List searchByExample(IPerceroObject theQueryObject, + List excludeProperties, String userId) throws SyncException { + return findByExample(theQueryObject, excludeProperties, userId); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public IPerceroObject systemCreateObject(IPerceroObject perceroObject) + throws SyncException { +// Session s = appSessionFactory.openSession(); + + try { + // Make sure object has an ID. + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + if (!mappedClass.hasGeneratedId && !StringUtils.hasText(perceroObject.getID())) + perceroObject.setID(UUID.randomUUID().toString()); + else { + // Check to see if item already exists. + IPerceroObject existingObject = readObjectFromDatabase(BaseDataObject.toClassIdPair(perceroObject), false); + if (existingObject != null) + { + populateToManyRelationships(perceroObject, true, null); + populateToOneRelationships(perceroObject, true, null); + return perceroObject; + } + } + + insertObjectIntoDatabase(perceroObject); + populateToManyRelationships(perceroObject, true, null); + populateToOneRelationships(perceroObject, true, null); + + // Now update the cache. + // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... + if (cacheTimeout > 0) { + String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); + if (cacheTimeout > 0) { + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + } + + Set keysToDelete = new HashSet(); + MappedClass nextMappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + Iterator itrToManyFields = nextMappedClass.toManyFields.iterator(); + while(itrToManyFields.hasNext()) { + MappedField nextMappedField = itrToManyFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + keysToDelete.add(nextKey); + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + keysToDelete.add(nextKey); + } + } + } + } + } + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + while(itrToOneFields.hasNext()) { + MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + keysToDelete.add(nextKey); + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + keysToDelete.add(nextKey); + } + } + } + } + } + + if (!keysToDelete.isEmpty()) { + cacheDataStore.deleteKeys(keysToDelete); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + + return perceroObject; + } + catch(PropertyValueException pve) { + log.error("Error creating object", pve); + + SyncDataException sde = new SyncDataException(SyncDataException.MISSING_REQUIRED_FIELD, SyncDataException.MISSING_REQUIRED_FIELD_CODE, "Missing required field " + pve.getPropertyName()); + sde.fieldName = pve.getPropertyName(); + throw sde; + } + catch(Exception e) { + log.error("Error creating object", e); + + SyncDataException sde = new SyncDataException(SyncDataException.CREATE_OBJECT_ERROR, SyncDataException.CREATE_OBJECT_ERROR_CODE); + throw sde; + } + } + +// private void deepCleanObject(IPerceroObject perceroObject, MappedClass mappedClass, Session s, String userId) { +// if (!(perceroObject instanceof IRootObject)) { +// for(MappedField nextMappedField : mappedClass.externalizableFields) { +// try { +// if (nextMappedField instanceof MappedFieldPerceroObject) { +// Object fieldValue = nextMappedField.getValue(perceroObject); +// if (fieldValue != null) { +// fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); +// nextMappedField.getSetter().invoke(perceroObject, fieldValue); +// } +// } +// else if (nextMappedField instanceof MappedFieldList) { +// Object fieldValue = nextMappedField.getValue(perceroObject); +// if (fieldValue != null) { +// fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); +// nextMappedField.getSetter().invoke(perceroObject, fieldValue); +// } +// } +// else if (nextMappedField instanceof MappedFieldMap) { +// Object fieldValue = nextMappedField.getValue(perceroObject); +// if (fieldValue != null) { +// fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); +// nextMappedField.getSetter().invoke(perceroObject, fieldValue); +// } +// } +// } catch(Exception e) { +// log.error("Error in postCreateObject " + mappedClass.className + "." + nextMappedField.getField().getName(), e); +// } +// } +// } +// } + + public IPerceroObject createObject(IPerceroObject perceroObject, String userId) throws SyncException { + boolean hasAccess = true; + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + if (mappedClass != null) { + if (mappedClass.getCreateQuery() != null && StringUtils.hasText(mappedClass.getCreateQuery().getQuery())){ + Session s = appSessionFactory.openSession(); + try { + Query createFilter = s.createQuery(mappedClass.getCreateQuery().getQuery()); + mappedClass.getCreateQuery().setQueryParameters(createFilter, perceroObject, userId); + Number createFilterResult = (Number) createFilter.uniqueResult(); + if (createFilterResult == null || createFilterResult.intValue() <= 0) + hasAccess = false; + } catch (Exception e) { + log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); + hasAccess = false; + } finally { + s.close(); + } + } + } + + if (hasAccess) { + return systemCreateObject(perceroObject); + } else { + return null; + } + } + + + + //////////////////////////////////////////////////// + // PUT + //////////////////////////////////////////////////// + public IPerceroObject putObject(IPerceroObject perceroObject, Map> changedFields, String userId) throws SyncException { + boolean hasAccess = true; + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + if (mappedClass != null) { + if (mappedClass.getUpdateQuery() != null && StringUtils.hasText(mappedClass.getUpdateQuery().getQuery())){ + Session s = appSessionFactory.openSession(); + try { + Query updateFilter = null; + if (mappedClass.getUpdateQuery() instanceof JpqlQuery) { + updateFilter = s.createQuery(mappedClass.getUpdateQuery().getQuery()); + } + else if (mappedClass.getUpdateQuery() instanceof SqlQuery) { + updateFilter = s.createSQLQuery(mappedClass.getUpdateQuery().getQuery()); + } + mappedClass.getUpdateQuery().setQueryParameters(updateFilter, perceroObject, userId); + Number updateFilterResult = (Number) updateFilter.uniqueResult(); + if (updateFilterResult == null || updateFilterResult.intValue() <= 0) + hasAccess = false; + } catch (Exception e) { + log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); + hasAccess = false; + } finally { + s.close(); + } + } + } + + if (hasAccess) { + return systemPutObject(perceroObject, changedFields); + } else { + return null; + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map> changedFields) throws SyncException { + + try { + updateObjectInDatabase(perceroObject, changedFields); // If write fails, an exception will be thrown. + + if (changedFields != null && !changedFields.isEmpty()) { + // Since changedFields was set, it is possible (and likely) that perceroObject is only PARTIALLY filled out, so load the full object. + // Re-fetch the full object from the database. + perceroObject = readObjectFromDatabase(BaseDataObject.toClassIdPair(perceroObject), false); + populateToManyRelationships(perceroObject, true, null); + populateToOneRelationships(perceroObject, true, null); + } + + // Now update the cache. + // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... + if (cacheTimeout > 0) { + // TODO: Also need to update the caches of anything object that is related to this object. + String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); + if (cacheDataStore.hasKey(key)) { + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + } + + // Iterate through each changed object and reset the cache for that object. + if (changedFields != null) { +// Iterator>> itrChangedFieldEntrySet = changedFields.entrySet().iterator(); +// Set keysToDelete = new HashSet(); +// while (itrChangedFieldEntrySet.hasNext()) { +// Map.Entry> nextEntry = itrChangedFieldEntrySet.next(); +// ClassIDPair thePair = nextEntry.getKey(); +// if (!thePair.comparePerceroObject(perceroObject)) { +// String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); +// keysToDelete.add(nextKey); +// } +// } + Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); + Set keysToDelete = new HashSet(); + while (itrChangedFieldKeyset.hasNext()) { + ClassIDPair thePair = itrChangedFieldKeyset.next(); + if (!thePair.comparePerceroObject(perceroObject)) { + String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); + keysToDelete.add(nextKey); + } + } + + if (!keysToDelete.isEmpty()) { + cacheDataStore.deleteKeys(keysToDelete); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + else { + // No changedFields? We should never get here? + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + Iterator itrToManyFields = mappedClass.toManyFields.iterator(); + while(itrToManyFields.hasNext()) { + MappedField nextMappedField = itrToManyFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + } + } + } + } + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + while(itrToOneFields.hasNext()) { + MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + } + } + } + } + } + } + + return perceroObject; + } catch (Exception e) { + log.error("Error putting object", e); + + SyncDataException sde = new SyncDataException(SyncDataException.UPDATE_OBJECT_ERROR, SyncDataException.UPDATE_OBJECT_ERROR_CODE); + throw sde; + } + } + + + + //////////////////////////////////////////////////// + // DELETE + //////////////////////////////////////////////////// + public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws SyncException { + Session s = appSessionFactory.openSession(); + + try { + IPerceroObject perceroObject = readObjectFromDatabase(theClassIdPair, true); +// IPerceroObject perceroObject = (IPerceroObject) s.get(theClassIdPair.getClassName(), theClassIdPair.getID()); + if (perceroObject == null) { + return true; + } + + boolean hasAccess = true; + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(theClassIdPair.getClassName()); + if (mappedClass != null) { + if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ + Query deleteFilter = null; + if (mappedClass.getDeleteQuery() instanceof JpqlQuery) { + deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); + } + else if (mappedClass.getDeleteQuery() instanceof SqlQuery) { + deleteFilter = s.createSQLQuery(mappedClass.getDeleteQuery().getQuery()); + } + mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, perceroObject, userId); + Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); + if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) + hasAccess = false; + } + } + + if (hasAccess) { + if (systemDeleteObject(perceroObject)) { + return true; + } + else { + return true; + } + } else { + log.warn("No access to delete object " + theClassIdPair.toString()); + return false; + } + } catch (Exception e) { + log.error("Error putting object", e); + return false; + } finally { + s.close(); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Boolean systemDeleteObject(IPerceroObject perceroObject) throws SyncException { + + Session s = null; + + try { + MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(perceroObject.getClass().getCanonicalName()); + if (mappedClass == null) { + log.warn("Missing MappedClass for " + perceroObject.getClass().getCanonicalName()); + throw new SyncException(SyncException.MISSING_MAPPED_CLASS_ERROR, SyncException.MISSING_MAPPED_CLASS_ERROR_CODE ); + } + + // TODO: Call the DAO for this. + String deleteQueryString = "DELETE FROM " + (StringUtils.hasText(mappedClass.tableSchema) ? mappedClass.tableSchema + "." : "") + mappedClass.tableName + " WHERE ID=:objectId"; + + s = appSessionFactory.openSession(); + Query query = s.createSQLQuery(deleteQueryString); + query.setParameter("objectId", perceroObject.getID()); + + int result = query.executeUpdate(); + + // Now delete from cache. + // Now update the cache. + // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... + if (cacheTimeout > 0) { + Set keysToDelete = new HashSet(); + + String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); + keysToDelete.add(key); + + Iterator itrToManyFields = mappedClass.toManyFields.iterator(); + while(itrToManyFields.hasNext()) { + MappedField nextMappedField = itrToManyFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + keysToDelete.add(nextKey); + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + keysToDelete.add(nextKey); + } + } + } + } + } + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + while(itrToOneFields.hasNext()) { + MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + keysToDelete.add(nextKey); + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + keysToDelete.add(nextKey); + } + } + } + } + } + + if (!keysToDelete.isEmpty()) { + cacheDataStore.deleteKeys(keysToDelete); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + + return true; + + } catch(Exception e) { + if (perceroObject != null) { + log.error("Unable to delete record from database: " + perceroObject.getClass().getCanonicalName() + ":" + perceroObject.getID(), e); + } + else { + log.error("Unable to delete record from database: NULL Object", e); + } + throw new SyncDataException(SyncDataException.DELETE_OBJECT_ERROR, SyncDataException.DELETE_OBJECT_ERROR_CODE); + } finally { + if (s != null && s.isOpen()) { + s.close(); + } + } + } + + + //////////////////////////////////////////////////// + // CLEAN + //////////////////////////////////////////////////// + @Override + public IPerceroObject cleanObject(IPerceroObject perceroObject, String userId) throws SyncException { + try { + if (((BaseDataObject) perceroObject).getIsClean()) { + perceroObject = findById(BaseDataObject.toClassIdPair(perceroObject), userId); + ((BaseDataObject) perceroObject).setIsClean(true); + } + + } catch(Exception e) { + throw new SyncException(e); + } + return perceroObject; + + } + + @Override + @SuppressWarnings("rawtypes") + public List cleanObject(List perceroObjects, String userId) throws SyncException { + try { + List results = new ArrayList(perceroObjects.size()); + + Map classPairs = new HashMap(); + + Iterator itrPerceroObjects = perceroObjects.iterator(); + while (itrPerceroObjects.hasNext()) { + IPerceroObject nextPerceroObject = itrPerceroObjects.next(); + if ( ((BaseDataObject)nextPerceroObject).getIsClean()) { + results.add(nextPerceroObject); + } + else { + ClassIDPairs pairs = classPairs.get(nextPerceroObject.getClass()); + if (pairs == null) { + pairs = new ClassIDPairs(); + pairs.setClassName(nextPerceroObject.getClass().getCanonicalName()); + classPairs.put(nextPerceroObject.getClass(), pairs); + } + pairs.addId(nextPerceroObject.getID()); + } + } + + Iterator> itrClassPairs = classPairs.entrySet().iterator(); + while (itrClassPairs.hasNext()) { + Entry nextEntrySet = itrClassPairs.next(); + + MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(nextEntrySet.getKey().getCanonicalName()); + if (mappedClass != null) { + results.addAll( mappedClass.getDataProvider().findByIds(nextEntrySet.getValue(), userId) ); + } + + } + + return results; + } catch(Exception e) { + throw new SyncException(e); + } + } + + + @SuppressWarnings("rawtypes") + public Map> getChangedMappedFields(IPerceroObject newObject) { + Map> result = new HashMap>(); + Collection baseObjectResult = null; + ClassIDPair basePair = new ClassIDPair(newObject.getID(), newObject.getClass().getCanonicalName()); + + String className = newObject.getClass().getCanonicalName(); + IPerceroObject oldObject = systemGetById(new ClassIDPair(newObject.getID(), className)); + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mc = mcm.getMappedClassByClassName(className); + Iterator itrMappedFields = mc.externalizableFields.iterator(); + while (itrMappedFields.hasNext()) { + MappedField nextMappedField = itrMappedFields.next(); + try { + Boolean fieldIsEqual = nextMappedField.compareObjects(oldObject, newObject); + if (!fieldIsEqual) { + if (baseObjectResult == null) { + baseObjectResult = new HashSet(); + result.put(basePair, baseObjectResult); + } + baseObjectResult.add(nextMappedField); + + // If this is a relationship field, then need to grab the old and new values. + if (nextMappedField.getReverseMappedField() != null) { + if (nextMappedField instanceof MappedFieldPerceroObject) { + MappedFieldPerceroObject nextMappedFieldPerceroObject = (MappedFieldPerceroObject) nextMappedField; + + IPerceroObject oldReversePerceroObject = (IPerceroObject) nextMappedFieldPerceroObject.getGetter().invoke(oldObject); + if (oldReversePerceroObject != null) { + ClassIDPair oldReversePair = new ClassIDPair(oldReversePerceroObject.getID(), oldReversePerceroObject.getClass().getCanonicalName()); + Collection oldReverseChangedFields = result.get(oldReversePair); + if (oldReverseChangedFields == null) { + oldReverseChangedFields = new HashSet(); + result.put(oldReversePair, oldReverseChangedFields); + } + oldReverseChangedFields.add(nextMappedField.getReverseMappedField()); + } + + IPerceroObject newReversePerceroObject = (IPerceroObject) nextMappedFieldPerceroObject.getGetter().invoke(newObject); + if (newReversePerceroObject != null) { + ClassIDPair newReversePair = new ClassIDPair(newReversePerceroObject.getID(), newReversePerceroObject.getClass().getCanonicalName()); + Collection changedFields = result.get(newReversePair); + if (changedFields == null) { + changedFields = new HashSet(); + result.put(newReversePair, changedFields); + } + changedFields.add(nextMappedField.getReverseMappedField()); + } + } + else if (nextMappedField instanceof MappedFieldList) { + MappedFieldList nextMappedFieldList = (MappedFieldList) nextMappedField; + + List oldReverseList = (List) nextMappedFieldList.getGetter().invoke(oldObject); + if (oldReverseList == null) + oldReverseList = new ArrayList(); + + List newReverseList = (List) nextMappedFieldList.getGetter().invoke(newObject); + if (newReverseList == null) + newReverseList = new ArrayList(); + + // Compare each item in the lists. + Collection oldChangedList = retrieveObjectsNotInCollection(oldReverseList, newReverseList); + Iterator itrOldChangedList = oldChangedList.iterator(); + while (itrOldChangedList.hasNext()) { + BaseDataObject nextOldChangedObject = (BaseDataObject) itrOldChangedList.next(); + ClassIDPair nextOldReversePair = BaseDataObject.toClassIdPair(nextOldChangedObject); + + // Old object is not in new list, so add to list of changed fields. + Collection changedFields = result.get(nextOldReversePair); + if (changedFields == null) { + changedFields = new HashSet(); + result.put(nextOldReversePair, changedFields); + } + changedFields.add(nextMappedField.getReverseMappedField()); + } + + Collection newChangedList = retrieveObjectsNotInCollection(newReverseList, oldReverseList); + Iterator itrNewChangedList = newChangedList.iterator(); + while (itrNewChangedList.hasNext()) { + BaseDataObject nextNewChangedObject = (BaseDataObject) itrNewChangedList.next(); + ClassIDPair nextNewReversePair = BaseDataObject.toClassIdPair(nextNewChangedObject); + + // Old object is not in new list, so add to list of changed fields. + Collection changedFields = result.get(nextNewReversePair); + if (changedFields == null) { + changedFields = new HashSet(); + result.put(nextNewReversePair, changedFields); + } + changedFields.add(nextMappedField.getReverseMappedField()); + } + } + } + } + } catch(Exception e) { + log.warn("Error getting changed field: " + nextMappedField.getField().getName(), e); + baseObjectResult.add(nextMappedField); + } + } + + return result; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Collection retrieveObjectsNotInCollection(Collection baseList, Collection compareToList) { + Collection result = new HashSet(); + Iterator itrBaseList = baseList.iterator(); + Iterator itrCompareToList = null; + boolean matchFound = false; + + while (itrBaseList.hasNext()) { + BaseDataObject nextBasePerceroObject = (BaseDataObject) itrBaseList.next(); + ClassIDPair nextBasePair = BaseDataObject.toClassIdPair(nextBasePerceroObject); + nextBasePerceroObject = (BaseDataObject) systemGetById(nextBasePair); + + itrCompareToList = compareToList.iterator(); + matchFound = false; + while (itrCompareToList.hasNext()) { + BaseDataObject nextCompareToPerceroObject = (BaseDataObject) itrCompareToList.next(); + nextCompareToPerceroObject = (BaseDataObject) systemGetById(BaseDataObject.toClassIdPair(nextCompareToPerceroObject)); + + if (nextBasePerceroObject.getClass() == nextCompareToPerceroObject.getClass() && nextBasePerceroObject.getID().equalsIgnoreCase(nextCompareToPerceroObject.getID())) { + matchFound = true; + break; + } + } + + if (!matchFound) { + result.add(nextBasePerceroObject); + } + } + + return result; + } + + + /* (non-Javadoc) + * @see com.percero.agents.sync.services.IDataProvider#findAllRelatedObjects(com.percero.framework.vo.IPerceroObject, com.percero.agents.sync.metadata.MappedField, java.lang.Boolean, java.lang.String) + */ + @SuppressWarnings("unchecked") +// @Override + public List findAllRelatedObjects(IPerceroObject perceroObject, MappedField mappedField, Boolean shellOnly, String userId) throws SyncException { + List result = new ArrayList(); + + if (!StringUtils.hasText(perceroObject.getID())) { + // No valid ID on the object, so can't search for it. + return result; + } + + // The reverse mapped field should be the MappedField on the target object, the one that this MUST be the data provider for. + MappedField reverseMappedField = mappedField.getReverseMappedField(); + if (reverseMappedField == null) { + // No reverse mapped field, meaning there is nothing to do. + return result; + } + + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(reverseMappedField.getMappedClass().dataProviderName); + result = dataProvider.getAllByRelationship(reverseMappedField, BaseDataObject.toClassIdPair(perceroObject), shellOnly, userId); + + return result; + } + + public List getAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException { + IDataAccessObject dao = daoRegistry.getDataAccessObject(mappedField.getMappedClass().className); + return dao.getAllByRelationship(mappedField, targetClassIdPair, shellOnly, userId); + } + + + protected boolean isMappedFieldInChangedFields(IPerceroObject perceroObject, MappedField nextMappedField, Map> changedFields) { + Iterator>> itrChangedFields = changedFields.entrySet().iterator(); + while (itrChangedFields.hasNext()) { + Entry> nextChangedFieldEntry = itrChangedFields.next(); + + if (!nextChangedFieldEntry.getKey().comparePerceroObject(perceroObject)) { + // Not the same object. + continue; + } + + for(MappedField nextChangedField : nextChangedFieldEntry.getValue()) { + if ( StringUtils.hasText(nextMappedField.getColumnName()) && nextMappedField.getColumnName().equalsIgnoreCase(nextChangedField.getColumnName()) ) { + // We have found our field. + return true; + } + else if ( StringUtils.hasText(nextMappedField.getJoinColumnName()) && nextMappedField.getJoinColumnName().equalsIgnoreCase(nextChangedField.getJoinColumnName()) ) { + // We have found our field. + return true; + } + } + } + + return false; + } + + + /** + * Populates all the *-TO-MANY relationships on the specified object. All TO-MANY relationships have their + * relationship data stored on the other side of the relationship, so we have to go those dataProvider and + * ask for the objects. + * + * @param perceroObject + * @param userId + * @throws SyncException + * @throws IllegalArgumentException + * @throws IllegalAccessException + * @throws InvocationTargetException + */ + public void populateToManyRelationships(IPerceroObject perceroObject, Boolean shellOnly, + String userId) throws SyncException, IllegalArgumentException, + IllegalAccessException, InvocationTargetException { + if (perceroObject == null || !StringUtils.hasText(perceroObject.getID())) { + // Invalid object. + log.warn("Invalid object in populateToManyRelationships"); + return; + } + + MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(perceroObject.getClass().getCanonicalName()); + for(MappedField nextToManyMappedField : mappedClass.toManyFields) { + + // TODO: Take into account Access Rights. + List allRelatedObjects = findAllRelatedObjects(perceroObject, nextToManyMappedField, shellOnly, userId); + nextToManyMappedField.getSetter().invoke(perceroObject, allRelatedObjects); + } + } + + public void populateToOneRelationships(IPerceroObject perceroObject, Boolean shellOnly, + String userId) throws SyncException, IllegalArgumentException, + IllegalAccessException, InvocationTargetException { + if (perceroObject == null || !StringUtils.hasText(perceroObject.getID())) { + // Invalid object. + log.warn("Invalid object in populateToOneRelationships"); + return; + } + + MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(perceroObject.getClass().getCanonicalName()); + for(MappedFieldPerceroObject nextToOneMappedField : mappedClass.toOneFields) { + // If perceroObject is the "owner" of this relationship, then we have all the data necessary here. + if (nextToOneMappedField.isSourceEntity()) { +// if (!shellOnly || true) { +// // We want more than a Shell object, so ask the dataProvider of the mappedField for that object. +// IDataProvider dataProvider = nextToOneMappedField.getReverseMappedField().getMappedClass().getDataProvider(); +// IPerceroObject relatedPerceroObject = nextToOneMappedField.getPerceroObjectValue(perceroObject); +// relatedPerceroObject = dataProvider.systemGetById(BaseDataObject.toClassIdPair(relatedPerceroObject)); +// nextToOneMappedField.getSetter().invoke(perceroObject, relatedPerceroObject); +// +// if (!((BaseDataObject)perceroObject).getIsClean()) { +// ((BaseDataObject)perceroObject).setIsClean(true); +// dataProvider.populateToManyRelationships(relatedPerceroObject, false, userId); +// dataProvider.populateToOneRelationships(relatedPerceroObject, false, userId); +// } +// +// // Make sure the reverse relationship is mapped. +// if (nextToOneMappedField.getReverseMappedField() != null) { +// if (nextToOneMappedField.getReverseMappedField() instanceof MappedFieldPerceroObject) { +// // OneToOne, so just set reverse value. +// nextToOneMappedField.getReverseMappedField().getSetter().invoke(relatedPerceroObject, perceroObject); +// } +// else { +// // OneToMany/ManyToOne, so need to swap out of list. +// List reverseList = (List) nextToOneMappedField.getReverseMappedField().getValue(relatedPerceroObject); +// if (reverseList == null) { +// reverseList = new ArrayList(); +// nextToOneMappedField.getReverseMappedField().getSetter().invoke(relatedPerceroObject, reverseList); +// reverseList.add(perceroObject); +// } +// else { +// boolean objectFound = false; +// for(int i=0; i allRelatedObjects = findAllRelatedObjects(perceroObject, nextToOneMappedField, shellOnly, userId); + IPerceroObject relatedPerceroObject = null; + if (allRelatedObjects != null && !allRelatedObjects.isEmpty()) { + relatedPerceroObject = allRelatedObjects.get(0); + } + nextToOneMappedField.getSetter().invoke(perceroObject, relatedPerceroObject); + } + } + } + + protected void addObjectToCache(IPerceroObject nextPerceroObject) { + String key = RedisKeyUtils.classIdPair(nextPerceroObject.getClass().getCanonicalName(), nextPerceroObject.getID()); + if (cacheTimeout > 0) + cacheDataStore.setValue(key, ((BaseDataObject)nextPerceroObject).toJson()); + + // (Re)Set the expiration. + if (cacheTimeout > 0 && key != null) { + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + } + } + +} diff --git a/src/main/java/com/percero/agents/sync/services/DAORegistry.java b/src/main/java/com/percero/agents/sync/services/DAORegistry.java new file mode 100644 index 0000000..d97f0e2 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/services/DAORegistry.java @@ -0,0 +1,37 @@ +package com.percero.agents.sync.services; + +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.springframework.stereotype.Component; + +import com.percero.agents.sync.dao.IDataAccessObject; +import com.percero.framework.vo.IPerceroObject; + +@Component +public class DAORegistry { + + private static DAORegistry instance = null; + + public static DAORegistry getInstance() { + return instance; + } + + public DAORegistry() { + instance = this; + } + + private static Map> dataAccessObjects; + + @PostConstruct + public void init() { + // Init the data access objects here. + dataAccessObjects = new HashMap>(); + } + + public IDataAccessObject getDataAccessObject(String name) { + return dataAccessObjects.get(name); + } +} diff --git a/src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java b/src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java new file mode 100644 index 0000000..a0708fc --- /dev/null +++ b/src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java @@ -0,0 +1,1688 @@ +package com.percero.agents.sync.services; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtField; +import javassist.CtMethod; + +import org.apache.log4j.Logger; +import org.codehaus.jackson.map.ObjectMapper; +import org.hibernate.Criteria; +import org.hibernate.PropertyValueException; +import org.hibernate.Query; +import org.hibernate.QueryException; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.criterion.Criterion; +import org.hibernate.criterion.MatchMode; +import org.hibernate.criterion.Restrictions; +import org.hibernate.impl.SessionImpl; +import org.hibernate.type.Type; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import com.percero.agents.sync.access.RedisKeyUtils; +import com.percero.agents.sync.datastore.ICacheDataStore; +import com.percero.agents.sync.exceptions.SyncDataException; +import com.percero.agents.sync.exceptions.SyncException; +import com.percero.agents.sync.hibernate.AssociationExample; +import com.percero.agents.sync.hibernate.BaseDataObjectPropertySelector; +import com.percero.agents.sync.hibernate.SyncHibernateUtils; +import com.percero.agents.sync.metadata.IMappedClassManager; +import com.percero.agents.sync.metadata.JpqlQuery; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClassManagerFactory; +import com.percero.agents.sync.metadata.MappedField; +import com.percero.agents.sync.metadata.MappedFieldList; +import com.percero.agents.sync.metadata.MappedFieldMap; +import com.percero.agents.sync.metadata.MappedFieldPerceroObject; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.agents.sync.vo.ClassIDPair; +import com.percero.agents.sync.vo.ClassIDPairs; +import com.percero.agents.sync.vo.IJsonObject; +import com.percero.agents.sync.vo.IRootObject; +import com.percero.framework.metadata.IMappedQuery; +import com.percero.framework.vo.IPerceroObject; +import com.percero.framework.vo.PerceroList; + +@Component +public class HibernateDataProvider implements IDataProvider { + + // TODO: Better manage Hibernate Sessions (opening and closing). + + private static final Logger log = Logger.getLogger(HibernateDataProvider.class); + + public void initialize() + { + // Do nothing. + } + + public String getName() { + return "syncAgent"; + } + + @Autowired + ICacheDataStore cacheDataStore; + + @Autowired + Long cacheTimeout = Long.valueOf(60 * 60 * 24 * 14); // Two weeks + + @Autowired + ObjectMapper safeObjectMapper; + + @Autowired + SessionFactory appSessionFactory; + public void setAppSessionFactory(SessionFactory value) { + appSessionFactory = value; + } + + + @SuppressWarnings({ "rawtypes", "unchecked" }) + // TODO: @Transactional(readOnly=true) + public PerceroList getAllByName(Object aName, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception { + Session s = appSessionFactory.openSession(); + try { + returnTotal = true; + String aClassName = aName.toString(); + Query countQuery = null; + Query query = null; + Class theClass = MappedClass.forName(aName.toString()); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); + boolean isValidReadQuery = false; + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { + isValidReadQuery = true; + } + } + + /** + * readAllQuery optimization + * You can now define a readAllQuery on a class to imporove it's initial download time + * for briefcase mode. + * + * Only supports plain SQL for now + */ + if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ + if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ + throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); + } + + log.debug("Using readAllQuery: "+aClassName); + String selectQueryString = mappedClass.getReadAllQuery().getQuery(); + + String countQueryString = "select count(*) from ("+selectQueryString+") as U"; + + // Add the limit clause + if (pageSize != null && pageNumber != null && pageSize.intValue() > 0) { + int offset = pageSize.intValue() * pageNumber.intValue(); + selectQueryString += " limit "+pageSize+" OFFSET "+offset; + } + + query = s.createSQLQuery(selectQueryString).addEntity(theClass); + countQuery = s.createSQLQuery(countQueryString); + + query.setParameter("userId", userId); + countQuery.setParameter("userId", userId); + } + else + if (theClass != null) { + String countQueryString = ""; + if (returnTotal) + countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; + String queryString = "SELECT getAllResult FROM " + aClassName + " getAllResult"; + + // If the Read Query/Filter uses the ID, then we need to check against each ID here. + if (isValidReadQuery) { + String queryFilterString = mappedClass.getReadQuery().getQuery(); + if (mappedClass.getReadQuery().getUseId()) { + // Need to replace :id with + queryFilterString = queryFilterString.replaceAll(":id", "getAllResult.ID"); + queryFilterString = queryFilterString.replaceAll(":Id", "getAllResult.ID"); + queryFilterString = queryFilterString.replaceAll(":iD", "getAllResult.ID"); + queryFilterString = queryFilterString.replaceAll(":ID", "getAllResult.ID"); + } + String countQueryFilterString = ""; + if (returnTotal) + countQueryFilterString = queryFilterString; + queryFilterString = queryString + " WHERE (" + queryFilterString + ") > 0 ORDER BY getAllResult.ID"; + + if (returnTotal) { + countQueryFilterString = countQueryString + " WHERE (" + countQueryFilterString + ") > 0"; + countQuery = s.createQuery(countQueryFilterString); + } + query = s.createQuery(queryFilterString); + mappedClass.getReadQuery().setQueryParameters(query, null, userId); + mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); + } + else { + queryString += " ORDER BY getAllResult.ID"; + if (returnTotal) { + countQueryString += " ORDER BY ID"; + countQuery = s.createQuery(countQueryString); + } + query = s.createQuery(queryString); + } + if (pageSize != null && pageNumber != null && pageSize.intValue() > 0) { + int pageValue = pageSize.intValue() * pageNumber.intValue(); + query.setFirstResult(pageValue); + query.setMaxResults(pageSize.intValue()); + } + } + + if (query != null) { + + log.debug("Get ALL: "+aClassName); + long t1 = new Date().getTime(); + List list = query.list(); + long t2 = new Date().getTime(); + log.debug("Query Time: "+(t2-t1)); + PerceroList result = new PerceroList( (List) SyncHibernateUtils.cleanObject(list, s, userId) ); + long t3 = new Date().getTime(); + log.debug("Clean Time: "+(t3-t2)); + + result.setPageNumber(pageNumber); + result.setPageSize(pageSize); + + if (returnTotal && pageSize != null && pageNumber != null && pageSize.intValue() > 0){ + result.setTotalLength(((Number)countQuery.uniqueResult()).intValue()); + log.debug("Total Obs: "+result.getTotalLength()); + } + else + result.setTotalLength(result.size()); + return result; + } + else { + return null; + } + + } catch (Exception e) { + log.error("Unable to getAllByName", e); + } finally { + s.close(); + } + + return null; + } + + @SuppressWarnings({ "rawtypes" }) + // TODO: @Transactional(readOnly=true) + public Integer countAllByName(String aClassName, String userId) throws Exception { + Session s = appSessionFactory.openSession(); + try { + Query countQuery = null; + Class theClass = MappedClass.forName(aClassName); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); + boolean isValidReadQuery = false; + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { + isValidReadQuery = true; + } + } + + if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ + if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ + throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); + } + + String selectQueryString = mappedClass.getReadAllQuery().getQuery(); + + String countQueryString = "select count(*) from ("+selectQueryString+") as U"; + + countQuery = s.createSQLQuery(countQueryString); + countQuery.setParameter("userId", userId); + } + else if (theClass != null) { + String countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; + + // If the Read Query/Filter uses the ID, then we need to check against each ID here. + if (isValidReadQuery) { + String queryFilterString = mappedClass.getReadQuery().getQuery(); + if (mappedClass.getReadQuery().getUseId()) { + // Need to replace :id with + queryFilterString = queryFilterString.replaceAll(":id", "getAllResult.ID"); + queryFilterString = queryFilterString.replaceAll(":Id", "getAllResult.ID"); + queryFilterString = queryFilterString.replaceAll(":iD", "getAllResult.ID"); + queryFilterString = queryFilterString.replaceAll(":ID", "getAllResult.ID"); + } + String countQueryFilterString = queryFilterString; + countQueryFilterString = countQueryString + " WHERE (" + countQueryFilterString + ") > 0"; + + countQuery = s.createQuery(countQueryFilterString); + mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); + } + else { + countQueryString += " ORDER BY ID"; + countQuery = s.createQuery(countQueryString); + } + } + + if (countQuery != null) { +// log.debug(countQuery.toString()); + Integer result = ((Number)countQuery.uniqueResult()).intValue(); + return result; + } + else { + return null; + } + + } catch (Exception e) { + log.error("Unable to countAllByName", e); + } finally { + s.close(); + } + + return 0; + } + + public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String userId) { + Session s = appSessionFactory.openSession(); + try { + if (mappedClass != null) { + for(IMappedQuery nextQuery : mappedClass.queries) + { + if (queryName.equalsIgnoreCase(nextQuery.getQueryName())) + { + Query readFilter = s.createQuery(nextQuery.getQuery()); + nextQuery.setQueryParameters(readFilter, queryArguments, userId, queryArguments, (SessionImpl)s); + return processQueryResults(mappedClass.className + "_" + queryName, readFilter, readFilter.list()); + } + } + } + } catch (Exception e) { + log.error("Unable to runQuery", e); + } finally { + if (s != null && s.isOpen()) + s.close(); + } + + return null; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected static List processQueryResults(String resultClassName, Query updateFilter, List updateFilterResult) throws Exception { + String[] returnAliases = updateFilter.getReturnAliases(); + Type[] returnTypes = updateFilter.getReturnTypes(); + + String[] fieldNames = new String[returnAliases.length]; + String[] getMethodNames = new String[returnAliases.length]; + String[] setMethodNames = new String[returnAliases.length]; + Class[] fieldClasses = new Class[returnAliases.length]; + + Class clazz = null; + ClassPool pool = null; + CtClass evalClass = null; + + if (returnAliases.length > 1) { + try { + clazz = MappedClass.forName(resultClassName); + } catch(Exception e) { + // Class must not yet exist, so let's create it. + } + + if (clazz == null) { + pool = ClassPool.getDefault(); + evalClass = pool.makeClass(resultClassName); + } + + // Create a new Class based on the result set. + for(int i = 0; i < returnAliases.length; i++) { + Type nextType = returnTypes[i]; + String nextTypeCanonicalName = nextType.getReturnedClass().getCanonicalName(); + String nextFieldName = returnAliases[i]; + try { + Integer.parseInt(nextFieldName); + nextFieldName = "field" + i; + } catch(NumberFormatException nfe) { + // Do nothing. Simply means the field name is not a Number. + } + String nextUpperFieldName = nextFieldName.substring(0, 1).toUpperCase() + nextFieldName.substring(1); + + fieldNames[i] = nextFieldName; + getMethodNames[i] = "get" + nextUpperFieldName; + setMethodNames[i] = "set" + nextUpperFieldName; + fieldClasses[i] = nextType.getReturnedClass(); + + if (evalClass != null) { + evalClass.addField(CtField.make("private " + fieldClasses[i].getCanonicalName() + " " + nextFieldName + ";", evalClass)); + evalClass.addMethod(CtMethod.make("public void " + setMethodNames[i] + "(" + fieldClasses[i].getCanonicalName() + " value) {this." + nextFieldName + " = value;}", evalClass)); + evalClass.addMethod(CtMethod.make("public " + nextTypeCanonicalName +" " + getMethodNames[i] + "() {return this." + nextFieldName + ";}", evalClass)); + } + } + + if (clazz == null && evalClass != null) { + clazz = evalClass.toClass(); + } + } + + List results = new ArrayList(); + + // Now populate the newly created objects. + for(Object nextResult : (List)updateFilterResult) { + + if (nextResult instanceof Object[]) { + Object nextObject = clazz.newInstance(); + for(int i = 0; i < returnAliases.length; i++) { + Class[] formalParams = new Class[] { fieldClasses[i] }; + Method setMethod = clazz.getDeclaredMethod(setMethodNames[i], formalParams); + setMethod.invoke(nextObject, ((Object[])nextResult)[i]); + } + + results.add(nextObject); + } else + results.add(nextResult); + } + + return results; + } + + //@SuppressWarnings({ "rawtypes", "unchecked" }) + public IPerceroObject findById(ClassIDPair classIdPair, String userId) { + boolean hasReadQuery = false; + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { + hasReadQuery = true; + } + } + + Session s = null; + try { + boolean hasAccess = true; + IPerceroObject result = systemGetById(classIdPair); + + if (result != null) { + if (hasReadQuery) { + if (s == null) + s = appSessionFactory.openSession(); + Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); + mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); + Number readFilterResult = (Number) readFilter.uniqueResult(); + if (readFilterResult == null || readFilterResult.intValue() <= 0) + hasAccess = false; + } + + if (hasAccess) { + if (s == null) + s = appSessionFactory.openSession(); +// ((BaseDataObject)result).setIsClean(false); + result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s, userId); + return result; + } + else { + return null; + } + } + else { + return null; + } + } catch (Exception e) { + log.error("Unable to findById", e); + } finally { + if (s != null && s.isOpen()) + s.close(); + } + return null; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public IPerceroObject systemGetById(ClassIDPair classIdPair) { + Session s = null; + try { + Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); + + if (theClass != null) { + IPerceroObject result = retrieveFromRedisCache(classIdPair); + String key = null; + + if (result == null) { + s = appSessionFactory.openSession(); + result = (IPerceroObject) s.get(theClass, classIdPair.getID()); + + // Now put the object in the cache. + if (result != null) { + key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); + result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); + if (cacheTimeout > 0) + cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); + } + else { + // Not necessarily a problem but could be helpful when debugging. + log.debug("Unable to retrieve object from database: " + classIdPair.toJson()); + } + } + else { + key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); + } + + // (Re)Set the expiration. + if (cacheTimeout > 0 && key != null) { + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + } + + return result; + } else { + return null; + } + } catch (Exception e) { + log.error("Unable to systemGetById: "+classIdPair.toJson(), e); + } finally { + if (s != null && s.isOpen()) + s.close(); + } + return null; + } + + @SuppressWarnings({ "rawtypes" }) + public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, Class theClass, Session s) { + Boolean sessionAlreadyOpen = false; + try { + if (theClass != null) { + IPerceroObject result = retrieveFromRedisCache(classIdPair); + String key = null; + + if (result == null) { + if (s == null || !s.isOpen()) { + s = appSessionFactory.openSession(); + } + else { + sessionAlreadyOpen = true; + } + result = (IPerceroObject) s.get(theClass, classIdPair.getID()); + + // Now put the object in the cache. + if (result != null) { + key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); + result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); + if (cacheTimeout > 0) + cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); + } + else { + log.warn("Unable to retrieve object from database: " + classIdPair.toString()); + } + } + else { + key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); + } + + // (Re)Set the expiration. + if (cacheTimeout > 0 && key != null) { + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + } + + return result; + } else { + return null; + } + } catch (Exception e) { + log.error("Unable to systemGetById: "+classIdPair.toJson(), e); + } finally { + // Only close the session if it wasn't already open. + if (!sessionAlreadyOpen) { + if (s != null && s.isOpen()) { + s.close(); + } + } + } + return null; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Exception { + IPerceroObject result = null; + if (cacheTimeout > 0) { + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + Class theClass = MappedClass.forName(classIdPair.getClassName()); + MappedClass mc = mcm.getMappedClassByClassName(classIdPair.getClassName()); + + String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); + String jsonObjectString = (String) cacheDataStore.getValue(key); + if (jsonObjectString != null) { + if (IJsonObject.class.isAssignableFrom(theClass)) { + IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); + jsonObject.fromJson(jsonObjectString); + result = (IPerceroObject) jsonObject; + } + else { + result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); + } + } + else { + // Check MappedClass' child classes. + Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); + while (itrChildMappedClasses.hasNext()) { + MappedClass nextChildMc = itrChildMappedClasses.next(); + key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); + jsonObjectString = (String) cacheDataStore.getValue(key); + if (jsonObjectString != null) { + result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); + return result; + } + } + } + } + + return result; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Map retrieveFromRedisCache(ClassIDPairs classIdPairs, Boolean pleaseSetTimeout) throws Exception { + Map result = new HashMap(classIdPairs.getIds().size()); + + if (cacheTimeout > 0) { + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + Class theClass = MappedClass.forName(classIdPairs.getClassName()); + MappedClass mc = mcm.getMappedClassByClassName(classIdPairs.getClassName()); + + Set keys = new HashSet(classIdPairs.getIds().size()); + Iterator itrIds = classIdPairs.getIds().iterator(); + while (itrIds.hasNext()) { + String nextId = itrIds.next(); + String nextKey = RedisKeyUtils.classIdPair(classIdPairs.getClassName(), nextId); + keys.add(nextKey); + + // Check MappedClass' child classes. + Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); + while (itrChildMappedClasses.hasNext()) { + MappedClass nextChildMc = itrChildMappedClasses.next(); + if (nextChildMc.clazz == BaseDataObject.class) { + // Reached the top level, so break. + break; + } + nextKey = RedisKeyUtils.classIdPair(nextChildMc.className, nextId); + keys.add(nextKey); + } + } + +// String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); + List jsonObjectStrings = cacheDataStore.getValues(keys); + Iterator itrJsonObjectStrings = jsonObjectStrings.iterator(); + while (itrJsonObjectStrings.hasNext()) { + String jsonObjectString = (String) itrJsonObjectStrings.next(); + if (jsonObjectString != null) { + if (IJsonObject.class.isAssignableFrom(theClass)) { + IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); + jsonObject.fromJson(jsonObjectString); + result.put( (((IPerceroObject) jsonObject).getID()), (IPerceroObject) jsonObject ); + } + else { + IPerceroObject nextPerceroObject = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); + result.put( nextPerceroObject.getID(), nextPerceroObject); + } + + } +// else { +// // Check MappedClass' child classes. +// Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); +// while (itrChildMappedClasses.hasNext()) { +// MappedClass nextChildMc = itrChildMappedClasses.next(); +// key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); +// jsonObjectString = (String) redisDataStore.getValue(key); +// if (jsonObjectString != null) { +// result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); +// return result; +// } +// } +// } + } + + if (pleaseSetTimeout) { + cacheDataStore.expire(keys, cacheTimeout, TimeUnit.SECONDS); + } + } + + return result; + } + + @SuppressWarnings({ "rawtypes" }) + public Boolean getReadAccess(ClassIDPair classIdPair, String userId) { + Session s = appSessionFactory.openSession(); + try { + Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); + + if (theClass != null) { + IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); + + boolean hasAccess = (parent != null); + + if (hasAccess) { + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ + Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); + mappedClass.getReadQuery().setQueryParameters(readFilter, parent, userId); + Number readFilterResult = (Number) readFilter.uniqueResult(); + if (readFilterResult == null || readFilterResult.intValue() <= 0) + hasAccess = false; + } + } + } + + return hasAccess; + } + } catch (Exception e) { + log.error("Unable to getReadAccess", e); + } finally { + s.close(); + } + return false; + } + + @SuppressWarnings({ "rawtypes" }) + public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { + Session s = appSessionFactory.openSession(); + try { + Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); + + if (theClass != null) { + IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); + + if (parent == null) + return true; + + boolean hasAccess = true; + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); + if (mappedClass != null) { + if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ + Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); + mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, parent, userId); + Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); + if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) + hasAccess = false; + } + } + + return hasAccess; + } + } catch (Exception e) { + log.error("Unable to getDeleteAccess", e); + } finally { + s.close(); + } + return false; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public List findByIds(ClassIDPairs classIdPairs, String userId) { + List result = null; + + boolean hasAccess = true; + Class theClass = null; + try { + theClass = MappedClass.forName(classIdPairs.getClassName()); + } catch (ClassNotFoundException e2) { + log.error("Unable to get Class from class name " + classIdPairs.getClassName(), e2); + return result; + } + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPairs.getClassName()); + boolean isValidReadQuery = false; + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { + isValidReadQuery = true; + } + + } + + if (hasAccess) { + if (theClass != null) { + Set idsSet = new HashSet(classIdPairs.getIds().size()); + idsSet.addAll(classIdPairs.getIds()); + + try { + // Attempt to get as many from the cache as possible... + Map cachedObjects = retrieveFromRedisCache(classIdPairs, true); + + if (!cachedObjects.isEmpty()) { + result = new ArrayList(cachedObjects.size()); + List cachedResults = new ArrayList(cachedObjects.size()); + cachedResults.addAll(cachedObjects.values()); + idsSet.removeAll(cachedObjects.keySet()); + + // If there is a read query, we need to check each object through that query. + if (isValidReadQuery) { + Session s = null; + try { + // Need to clean each result for the user. + // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function + s = appSessionFactory.openSession(); + + Iterator itrCachedResults = cachedResults.iterator(); + while (itrCachedResults.hasNext()) { + IPerceroObject nextCachedResult = itrCachedResults.next(); + if (isValidReadQuery) { + Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); + mappedClass.getReadQuery().setQueryParameters(readFilter, nextCachedResult, userId); + Number readFilterResult = (Number) readFilter.uniqueResult(); + if (readFilterResult == null || readFilterResult.intValue() <= 0) + hasAccess = false; + } + + if (hasAccess) { + result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); + } + } + } catch (Exception e) { + log.error("Error cleaning object for user in findByIds", e); + } finally { + if (s != null && s.isOpen()) { + s.close(); + } + } + } + else { + // This class has relationship objects that need to be cleaned. + if (!mappedClass.getReadAccessRightsFieldReferences().isEmpty()) { + Session s = null; + try { + // Need to clean each result for the user. + // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function + // TODO: Maybe only clean relationships that are in mappedClass.readAccessRightsFieldReferences? + s = appSessionFactory.openSession(); + + Iterator itrCachedResults = cachedResults.iterator(); + while (itrCachedResults.hasNext()) { + IPerceroObject nextCachedResult = itrCachedResults.next(); + result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); + } + } catch (Exception e) { + log.error("Error cleaning object for user in findByIds", e); + } finally { + if (s != null && s.isOpen()) { + s.close(); + } + } + } + else { + // This class has NO read access query AND has NO relationships that require cleaning, + // since this object is completely retrieved from redis, we can send as-is. + // Though this may seem rare, this is probably a very common path. + result.addAll(cachedResults); + } + } + } + } catch (Exception e1) { + // We errored out here, but we can still try and retrieve from the database. + log.error("Error retrieving objects from redis cache, attempting to retrieve from database", e1); + } + + // Now get the rest from the database. + if (!idsSet.isEmpty()) { + String queryString = "SELECT findByIdsResult FROM " + classIdPairs.getClassName() + " findByIdsResult WHERE findByIdsResult.ID IN (:idsSet)"; + + // Open the database session. + Session s = null; + try { + s = appSessionFactory.openSession(); + Query query = null; + + // If the Read Query/Filter uses the ID, then we need to check against each ID here. + if (isValidReadQuery) { + String queryFilterString = mappedClass.getReadQuery().getQuery(); + if (mappedClass.getReadQuery().getUseId()) { + // Need to replace :id with + queryFilterString = queryFilterString.replaceAll(":id", "findByIdsResult.ID"); + queryFilterString = queryFilterString.replaceAll(":Id", "findByIdsResult.ID"); + queryFilterString = queryFilterString.replaceAll(":iD", "findByIdsResult.ID"); + queryFilterString = queryFilterString.replaceAll(":ID", "findByIdsResult.ID"); + } + queryFilterString = queryString + " AND (" + queryFilterString + ") > 0"; + + query = s.createQuery(queryFilterString); + mappedClass.getReadQuery().setQueryParameters(query, null, userId); + } + else { + query = s.createQuery(queryString); + } + + query.setParameterList("idsSet", idsSet); + List queryResult = query.list(); + List cleanedDatabaseObjects = (List) SyncHibernateUtils.cleanObject(queryResult, s, userId); + + // Need to put results into cache. + if (cacheTimeout > 0) { + Map mapJsonObjectStrings = new HashMap(cleanedDatabaseObjects.size()); + Iterator itrDatabaseObjects = cleanedDatabaseObjects.iterator(); + while (itrDatabaseObjects.hasNext()) { + IPerceroObject nextDatabaseObject = itrDatabaseObjects.next(); + String nextCacheKey = RedisKeyUtils.classIdPair(nextDatabaseObject.getClass().getCanonicalName(), nextDatabaseObject.getID()); + + mapJsonObjectStrings.put(nextCacheKey, ((BaseDataObject)nextDatabaseObject).toJson()); + } + + // Store the objects in redis. + cacheDataStore.setValues(mapJsonObjectStrings); + // (Re)Set the expiration. + cacheDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); + } + + if (result == null) { + result = cleanedDatabaseObjects; + } + else { + result.addAll(cleanedDatabaseObjects); + } + } catch (QueryException qe) { + log.error("Unable to findByIds", qe); + } catch (Exception e) { + log.error("Unable to findByIds", e); + } finally { + if (s != null && s.isOpen()) { + s.close(); + } + } + } + } + } + + return result; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId) { + Session s = appSessionFactory.openSession(); + try { + Class objectClass = theQueryObject.getClass(); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(objectClass.getName()); + if (mappedClass != null) { + Iterator itr = mappedClass.uniqueConstraints.iterator(); + while(itr.hasNext()) { + Criteria criteria = null; + Object nextConstraint = itr.next(); + if (nextConstraint instanceof MappedField) { + MappedField nextConstraintField = (MappedField) nextConstraint; + Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); + if (nextConstraintFieldValue != null) { + if (criteria == null) + criteria = s.createCriteria(objectClass); + Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); + criteria.add(uniqueFieldValue); + } + } + else if (nextConstraint instanceof List) { + List listMappedFields = (List) nextConstraint; + Iterator itrMappedFields = listMappedFields.iterator(); + while(itrMappedFields.hasNext()) { + MappedField nextConstraintField = itrMappedFields.next(); + Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); + if (nextConstraintFieldValue != null) { + if (criteria == null) + criteria = s.createCriteria(objectClass); + Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); + criteria.add(uniqueFieldValue); + } + } + } + + if (criteria != null) { + criteria.setMaxResults(1); + Object result = criteria.uniqueResult(); + if (result != null) { + // Make sure user has access. + boolean hasAccess = true; + if (mappedClass != null) { + if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ + Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); + mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); + Number readFilterResult = (Number) readFilter.uniqueResult(); + if (readFilterResult == null || readFilterResult.intValue() <= 0) + hasAccess = false; + } + } + + if (hasAccess) { + result = SyncHibernateUtils.cleanObject(result, s, userId); + return (IPerceroObject) result; + } + } + } + } + } + } catch (Exception e) { + log.error("Unable to findByExample", e); + } finally { + s.close(); + } + + return null; + } + + // TODO: Add permissions check. + @SuppressWarnings({ "unchecked" }) + public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId) { + Session s = appSessionFactory.openSession(); + try { + Criteria criteria = s.createCriteria(theQueryObject.getClass()); + AssociationExample example = AssociationExample.create(theQueryObject); + BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); + example.setPropertySelector(propertySelector); + criteria.add(example); + + List result = criteria.list(); + result = (List) SyncHibernateUtils.cleanObject(result, s, userId); + + return (List) result; + } catch (Exception e) { + log.error("Unable to findByExample", e); + } finally { + s.close(); + } + + return null; + } + + @SuppressWarnings({ "unchecked" }) + public List systemFindByExample(IPerceroObject theQueryObject, List excludeProperties) { + Session s = appSessionFactory.openSession(); + try { + Criteria criteria = s.createCriteria(theQueryObject.getClass()); + AssociationExample example = AssociationExample.create(theQueryObject); + BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); + example.setPropertySelector(propertySelector); + criteria.add(example); + + List result = criteria.list(); + result = (List) SyncHibernateUtils.cleanObject(result, s); + + return (List) result; + } catch (Exception e) { + log.error("Unable to findByExample", e); + } finally { + s.close(); + } + + return null; + } + + @SuppressWarnings("unchecked") + public List searchByExample(IPerceroObject theQueryObject, + List excludeProperties, String userId) { + Session s = appSessionFactory.openSession(); + try { + Criteria criteria = s.createCriteria(theQueryObject.getClass()); + AssociationExample example = AssociationExample.create(theQueryObject); + BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); + example.setPropertySelector(propertySelector); + example.enableLike(MatchMode.ANYWHERE); + criteria.add(example); + + List result = criteria.list(); + result = (List) SyncHibernateUtils.cleanObject(result, s, userId); + + return result; + } catch (Exception e) { + log.error("Unable to searchByExample", e); + } finally { + s.close(); + } + + return null; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public IPerceroObject systemCreateObject(IPerceroObject perceroObject) + throws SyncException { + Session s = appSessionFactory.openSession(); + + try { + // Make sure object has an ID. + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + if (!mappedClass.hasGeneratedId && !StringUtils.hasText(perceroObject.getID())) + perceroObject.setID(UUID.randomUUID().toString()); + else { + // Check to see if item already exists. + Object existingObject = s.get(perceroObject.getClass(), perceroObject.getID()); + if (existingObject != null) + { + perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(existingObject, s); + deepCleanObject(perceroObject, mappedClass, s, null); + return perceroObject; + } + } + + Transaction tx = s.beginTransaction(); + tx.begin(); + s.save(perceroObject); + tx.commit(); + + s.refresh(perceroObject); + + perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObject, s); + deepCleanObject(perceroObject, mappedClass, s, null); + + // Now update the cache. + // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... + if (cacheTimeout > 0) { + String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); + if (cacheTimeout > 0) { + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + } + + Set keysToDelete = new HashSet(); + MappedClass nextMappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + Iterator itrToManyFields = nextMappedClass.toManyFields.iterator(); + while(itrToManyFields.hasNext()) { + MappedField nextMappedField = itrToManyFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + keysToDelete.add(nextKey); + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + keysToDelete.add(nextKey); + } + } + } + } + } + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + while(itrToOneFields.hasNext()) { + MappedField nextMappedField = itrToOneFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + keysToDelete.add(nextKey); + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + keysToDelete.add(nextKey); + } + } + } + } + } + + if (!keysToDelete.isEmpty()) { + cacheDataStore.deleteKeys(keysToDelete); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + + return perceroObject; + } + catch(PropertyValueException pve) { + log.error("Error creating object", pve); + + SyncDataException sde = new SyncDataException(SyncDataException.MISSING_REQUIRED_FIELD, SyncDataException.MISSING_REQUIRED_FIELD_CODE, "Missing required field " + pve.getPropertyName()); + sde.fieldName = pve.getPropertyName(); + throw sde; + } + catch(Exception e) { + log.error("Error creating object", e); + + SyncDataException sde = new SyncDataException(SyncDataException.CREATE_OBJECT_ERROR, SyncDataException.CREATE_OBJECT_ERROR_CODE); + throw sde; + } + finally { + if (s != null && s.isOpen()) { + s.close(); + } + } + } + + private void deepCleanObject(IPerceroObject perceroObject, MappedClass mappedClass, Session s, String userId) { + if (!(perceroObject instanceof IRootObject)) { + for(MappedField nextMappedField : mappedClass.externalizableFields) { + try { + if (nextMappedField instanceof MappedFieldPerceroObject) { + Object fieldValue = nextMappedField.getValue(perceroObject); + if (fieldValue != null) { + fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); + nextMappedField.getSetter().invoke(perceroObject, fieldValue); + } + } + else if (nextMappedField instanceof MappedFieldList) { + Object fieldValue = nextMappedField.getValue(perceroObject); + if (fieldValue != null) { + fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); + nextMappedField.getSetter().invoke(perceroObject, fieldValue); + } + } + else if (nextMappedField instanceof MappedFieldMap) { + Object fieldValue = nextMappedField.getValue(perceroObject); + if (fieldValue != null) { + fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); + nextMappedField.getSetter().invoke(perceroObject, fieldValue); + } + } + } catch(Exception e) { + log.error("Error in postCreateObject " + mappedClass.className + "." + nextMappedField.getField().getName(), e); + } + } + } + } + + public IPerceroObject createObject(IPerceroObject perceroObject, String userId) throws SyncException { + boolean hasAccess = true; + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + if (mappedClass != null) { + if (mappedClass.getCreateQuery() != null && StringUtils.hasText(mappedClass.getCreateQuery().getQuery())){ + Session s = appSessionFactory.openSession(); + try { + Query createFilter = s.createQuery(mappedClass.getCreateQuery().getQuery()); + mappedClass.getCreateQuery().setQueryParameters(createFilter, perceroObject, userId); + Number createFilterResult = (Number) createFilter.uniqueResult(); + if (createFilterResult == null || createFilterResult.intValue() <= 0) + hasAccess = false; + } catch (Exception e) { + log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); + hasAccess = false; + } finally { + s.close(); + } + } + } + + if (hasAccess) { + return systemCreateObject(perceroObject); + } else { + return null; + } + } + + + + //////////////////////////////////////////////////// + // PUT + //////////////////////////////////////////////////// + public IPerceroObject putObject(IPerceroObject perceroObject, Map> changedFields, String userId) throws SyncException { + boolean hasAccess = true; + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + if (mappedClass != null) { + if (mappedClass.getUpdateQuery() != null && StringUtils.hasText(mappedClass.getUpdateQuery().getQuery())){ + Session s = appSessionFactory.openSession(); + try { + Query updateFilter = s.createQuery(mappedClass.getUpdateQuery().getQuery()); + mappedClass.getUpdateQuery().setQueryParameters(updateFilter, perceroObject, userId); + Number updateFilterResult = (Number) updateFilter.uniqueResult(); + if (updateFilterResult == null || updateFilterResult.intValue() <= 0) + hasAccess = false; + } catch (Exception e) { + log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); + hasAccess = false; + } finally { + s.close(); + } + } + } + + if (hasAccess) { + return systemPutObject(perceroObject, changedFields); + } else { + return null; + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map> changedFields) throws SyncException { + Session s = null; + + try { + s = appSessionFactory.openSession(); + Transaction tx = s.beginTransaction(); + tx.begin(); + try { + //s.evict(perceroObject); + //perceroObject.setID(perceroObject.getID()); + perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObject, s); + //s.persist(perceroObject); + //perceroObject = (IPerceroObject) s.merge(perceroObject); + } catch(Exception e) { + e.printStackTrace(); + } + //s.saveOrUpdate(perceroObject); + s.update(perceroObject); + tx.commit(); + + s.refresh(perceroObject); + + ((BaseDataObject)perceroObject).setIsClean(false); + perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObject, s); + + // Now update the cache. + // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... + if (cacheTimeout > 0) { + // TODO: Also need to update the caches of anything object that is related to this object. + String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); + if (cacheDataStore.hasKey(key)) { + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + } + + // Iterate through each changed object and reset the cache for that object. + if (changedFields != null) { +// Iterator>> itrChangedFieldEntrySet = changedFields.entrySet().iterator(); +// Set keysToDelete = new HashSet(); +// while (itrChangedFieldEntrySet.hasNext()) { +// Map.Entry> nextEntry = itrChangedFieldEntrySet.next(); +// ClassIDPair thePair = nextEntry.getKey(); +// if (!thePair.comparePerceroObject(perceroObject)) { +// String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); +// keysToDelete.add(nextKey); +// } +// } + Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); + Set keysToDelete = new HashSet(); + while (itrChangedFieldKeyset.hasNext()) { + ClassIDPair thePair = itrChangedFieldKeyset.next(); + if (!thePair.comparePerceroObject(perceroObject)) { + String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); + keysToDelete.add(nextKey); + } + } + + if (!keysToDelete.isEmpty()) { + cacheDataStore.deleteKeys(keysToDelete); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + else { + // No changedFields? We should never get here? + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + Iterator itrToManyFields = mappedClass.toManyFields.iterator(); + while(itrToManyFields.hasNext()) { + MappedField nextMappedField = itrToManyFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + } + } + } + } + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + while(itrToOneFields.hasNext()) { + MappedField nextMappedField = itrToOneFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + } + } + } + } + } + } + + return perceroObject; + } catch (Exception e) { + log.error("Error putting object", e); + + SyncDataException sde = new SyncDataException(SyncDataException.UPDATE_OBJECT_ERROR, SyncDataException.UPDATE_OBJECT_ERROR_CODE); + throw sde; + } finally { + s.close(); + } + } + + + + //////////////////////////////////////////////////// + // DELETE + //////////////////////////////////////////////////// + public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws SyncException { + Session s = appSessionFactory.openSession(); + + try { + IPerceroObject perceroObject = (IPerceroObject) s.get(theClassIdPair.getClassName(), theClassIdPair.getID()); + if (perceroObject == null) { + return true; + } + + boolean hasAccess = true; + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(theClassIdPair.getClassName()); + if (mappedClass != null) { + if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ + Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); + mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, perceroObject, userId); + Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); + if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) + hasAccess = false; + } + } + + if (hasAccess) { + if (systemDeleteObject(perceroObject)) { + return true; + } + else { + return true; + } + } else { + log.warn("No access to delete object " + theClassIdPair.toString()); + return false; + } + } catch (Exception e) { + log.error("Error putting object", e); + return false; + } finally { + s.close(); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Boolean systemDeleteObject(IPerceroObject perceroObject) throws SyncException { + Boolean result = false; + Session s = appSessionFactory.openSession(); + + try { + // Load the object. + IPerceroObject perceroObjectToDelete = (IPerceroObject) s.load(perceroObject.getClass().getName(), perceroObject.getID()); + + // Make sure all associated objects are loaded. + // Clean the object before deletion because otherwise it will fail. + perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObjectToDelete, s); + + Transaction tx = s.beginTransaction(); + tx.begin(); + s.delete(perceroObjectToDelete); + tx.commit(); + + // Now delete from cache. + // Now update the cache. + // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... + if (cacheTimeout > 0) { + Set keysToDelete = new HashSet(); + + String key = RedisKeyUtils.classIdPair(SyncHibernateUtils.getShell(perceroObject).getClass().getCanonicalName(), perceroObject.getID()); + keysToDelete.add(key); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(SyncHibernateUtils.getShell(perceroObject).getClass().getName()); + Iterator itrToManyFields = mappedClass.toManyFields.iterator(); + while(itrToManyFields.hasNext()) { + MappedField nextMappedField = itrToManyFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + keysToDelete.add(nextKey); + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + keysToDelete.add(nextKey); + } + } + } + } + } + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + while(itrToOneFields.hasNext()) { + MappedField nextMappedField = itrToOneFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + keysToDelete.add(nextKey); + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + keysToDelete.add(nextKey); + } + } + } + } + } + + if (!keysToDelete.isEmpty()) { + cacheDataStore.deleteKeys(keysToDelete); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + + result = true; + } catch (Exception e) { + log.error("Error deleting object", e); + + SyncDataException sde = new SyncDataException(SyncDataException.DELETE_OBJECT_ERROR, SyncDataException.DELETE_OBJECT_ERROR_CODE); + throw sde; + } finally { + s.close(); + } + + return result; + } + + /* + public Object cleanObject(Object object) { + return SyncHibernateUtils.cleanObject(object); + }*/ + + public Object cleanObject(Object object, Session s, String userId) { + try { + if (s == null) { + s = appSessionFactory.openSession(); + } + return SyncHibernateUtils.cleanObject(object, s, userId); + } catch(Exception e) { + log.warn("Error cleaning object", e); + return null; + } finally { + if (s != null && s.isOpen()) { + s.close(); + } + } + } + + + @SuppressWarnings("rawtypes") + public Map> getChangedMappedFields(IPerceroObject newObject) { + Map> result = new HashMap>(); + Collection baseObjectResult = null; + ClassIDPair basePair = new ClassIDPair(newObject.getID(), newObject.getClass().getCanonicalName()); + + String className = newObject.getClass().getCanonicalName(); + IPerceroObject oldObject = systemGetById(new ClassIDPair(newObject.getID(), className)); + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mc = mcm.getMappedClassByClassName(className); + Iterator itrMappedFields = mc.externalizableFields.iterator(); + while (itrMappedFields.hasNext()) { + MappedField nextMappedField = itrMappedFields.next(); + try { + Boolean fieldIsEqual = nextMappedField.compareObjects(oldObject, newObject); + if (!fieldIsEqual) { + if (baseObjectResult == null) { + baseObjectResult = new HashSet(); + result.put(basePair, baseObjectResult); + } + baseObjectResult.add(nextMappedField); + + // If this is a relationship field, then need to grab the old and new values. + if (nextMappedField.getReverseMappedField() != null) { + if (nextMappedField instanceof MappedFieldPerceroObject) { + MappedFieldPerceroObject nextMappedFieldPerceroObject = (MappedFieldPerceroObject) nextMappedField; + + IPerceroObject oldReversePerceroObject = (IPerceroObject) nextMappedFieldPerceroObject.getGetter().invoke(oldObject); + if (oldReversePerceroObject != null) { + ClassIDPair oldReversePair = new ClassIDPair(oldReversePerceroObject.getID(), oldReversePerceroObject.getClass().getCanonicalName()); + Collection oldReverseChangedFields = result.get(oldReversePair); + if (oldReverseChangedFields == null) { + oldReverseChangedFields = new HashSet(); + result.put(oldReversePair, oldReverseChangedFields); + } + oldReverseChangedFields.add(nextMappedField.getReverseMappedField()); + } + + IPerceroObject newReversePerceroObject = (IPerceroObject) nextMappedFieldPerceroObject.getGetter().invoke(newObject); + if (newReversePerceroObject != null) { + ClassIDPair newReversePair = new ClassIDPair(newReversePerceroObject.getID(), newReversePerceroObject.getClass().getCanonicalName()); + Collection changedFields = result.get(newReversePair); + if (changedFields == null) { + changedFields = new HashSet(); + result.put(newReversePair, changedFields); + } + changedFields.add(nextMappedField.getReverseMappedField()); + } + } + else if (nextMappedField instanceof MappedFieldList) { + MappedFieldList nextMappedFieldList = (MappedFieldList) nextMappedField; + + List oldReverseList = (List) nextMappedFieldList.getGetter().invoke(oldObject); + if (oldReverseList == null) + oldReverseList = new ArrayList(); + + List newReverseList = (List) nextMappedFieldList.getGetter().invoke(newObject); + if (newReverseList == null) + newReverseList = new ArrayList(); + + // Compare each item in the lists. + Collection oldChangedList = retrieveObjectsNotInCollection(oldReverseList, newReverseList); + Iterator itrOldChangedList = oldChangedList.iterator(); + while (itrOldChangedList.hasNext()) { + BaseDataObject nextOldChangedObject = (BaseDataObject) itrOldChangedList.next(); + ClassIDPair nextOldReversePair = BaseDataObject.toClassIdPair(nextOldChangedObject); + + // Old object is not in new list, so add to list of changed fields. + Collection changedFields = result.get(nextOldReversePair); + if (changedFields == null) { + changedFields = new HashSet(); + result.put(nextOldReversePair, changedFields); + } + changedFields.add(nextMappedField.getReverseMappedField()); + } + + Collection newChangedList = retrieveObjectsNotInCollection(newReverseList, oldReverseList); + Iterator itrNewChangedList = newChangedList.iterator(); + while (itrNewChangedList.hasNext()) { + BaseDataObject nextNewChangedObject = (BaseDataObject) itrNewChangedList.next(); + ClassIDPair nextNewReversePair = BaseDataObject.toClassIdPair(nextNewChangedObject); + + // Old object is not in new list, so add to list of changed fields. + Collection changedFields = result.get(nextNewReversePair); + if (changedFields == null) { + changedFields = new HashSet(); + result.put(nextNewReversePair, changedFields); + } + changedFields.add(nextMappedField.getReverseMappedField()); + } + } + } + } + } catch(Exception e) { + log.warn("Error getting changed field: " + nextMappedField.getField().getName(), e); + baseObjectResult.add(nextMappedField); + } + } + + return result; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Collection retrieveObjectsNotInCollection(Collection baseList, Collection compareToList) { + Collection result = new HashSet(); + Iterator itrBaseList = baseList.iterator(); + Iterator itrCompareToList = null; + boolean matchFound = false; + + while (itrBaseList.hasNext()) { + BaseDataObject nextBasePerceroObject = (BaseDataObject) itrBaseList.next(); + ClassIDPair nextBasePair = BaseDataObject.toClassIdPair(nextBasePerceroObject); + nextBasePerceroObject = (BaseDataObject) systemGetById(nextBasePair); + + itrCompareToList = compareToList.iterator(); + matchFound = false; + while (itrCompareToList.hasNext()) { + BaseDataObject nextCompareToPerceroObject = (BaseDataObject) itrCompareToList.next(); + nextCompareToPerceroObject = (BaseDataObject) systemGetById(BaseDataObject.toClassIdPair(nextCompareToPerceroObject)); + + if (nextBasePerceroObject.getClass() == nextCompareToPerceroObject.getClass() && nextBasePerceroObject.getID().equalsIgnoreCase(nextCompareToPerceroObject.getID())) { + matchFound = true; + break; + } + } + + if (!matchFound) { + result.add(nextBasePerceroObject); + } + } + + return result; + } +} diff --git a/src/main/java/com/percero/agents/sync/services/IDataProvider.java b/src/main/java/com/percero/agents/sync/services/IDataProvider.java index ec8b82f..49178ec 100644 --- a/src/main/java/com/percero/agents/sync/services/IDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/IDataProvider.java @@ -50,4 +50,21 @@ public interface IDataProvider { * @return */ public Map> getChangedMappedFields(IPerceroObject newObject); + + /** + * Given the mappedField, returns ALL objects in the relationship described by the mappedField. + * If shellOnly is TRUE, then only a shell object will be returned, which is an Object with only it's ID set. + * Will enforce access rights based on the userId. + * Returns a cleaned object, meaning all its relationships are filled in with shell objects. + * + * @param perceroObject + * @param mappedField + * @param shellOnly + * @param userId + * @return List + * @throws SyncException + */ + public List findAllRelatedObjects(IPerceroObject perceroObject, MappedField mappedField, Boolean shellOnly, String userId) throws SyncException; + + public List getAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException; } diff --git a/src/main/java/com/percero/amqp/PerceroAgentListener.java b/src/main/java/com/percero/amqp/PerceroAgentListener.java index d2974b5..ef8876a 100644 --- a/src/main/java/com/percero/amqp/PerceroAgentListener.java +++ b/src/main/java/com/percero/amqp/PerceroAgentListener.java @@ -36,6 +36,11 @@ */ @Component("perceroAgentListener") public class PerceroAgentListener implements MessageListener { + + private static PerceroAgentListener perceroAgentListener = null; + public static PerceroAgentListener getInstance() { + return perceroAgentListener; + } @Autowired AmqpTemplate template; @@ -114,6 +119,10 @@ public class PerceroAgentListener implements MessageListener { public static final String PROCESS_TRANSACTION = "processTransaction"; private static Logger logger = Logger.getLogger(PerceroAgentListener.class); + + public PerceroAgentListener() { + PerceroAgentListener.perceroAgentListener = this; + } /** * Message handling function diff --git a/src/main/java/com/percero/framework/metadata/IMappedQuery.java b/src/main/java/com/percero/framework/metadata/IMappedQuery.java index 9b27f07..d306209 100644 --- a/src/main/java/com/percero/framework/metadata/IMappedQuery.java +++ b/src/main/java/com/percero/framework/metadata/IMappedQuery.java @@ -1,7 +1,5 @@ package com.percero.framework.metadata; -import org.hibernate.Query; -import org.hibernate.impl.SessionImpl; public interface IMappedQuery { @@ -13,6 +11,6 @@ public interface IMappedQuery { public boolean getUseId(); - public void setQueryParameters(Query theQuery, Object theObject, String userId) throws Exception; - public void setQueryParameters(Query theQuery, Object theObject, String userId, Object[] params, SessionImpl s) throws Exception; + public String setQueryParameters(String theQuery, Object theObject, String userId) throws Exception; + public String setQueryParameters(String theQuery, Object theObject, String userId, Object[] params) throws Exception; } From 781b3701327a54fab9c54fff2e1a5a96aeff9e81 Mon Sep 17 00:00:00 2001 From: Jonathan Samples Date: Fri, 4 Sep 2015 15:11:57 -0700 Subject: [PATCH 08/20] Added some test infrastructure --- pom.xml | 16 + .../agents/sync/helpers/PostDeleteHelper.java | 33 +- .../jobs/UpdateTableConnectionFactory.java | 42 +-- .../agents/sync/jobs/UpdateTablePoller.java | 10 +- .../sync/jobs/UpdateTableProcessor.java | 257 ++++++++++++++ .../agents/sync/jobs/UpdateTableRow.java | 66 ++++ .../agents/sync/jobs/UpdateTableRowType.java | 8 + .../sync/jobs/UpdateTableProcessorTest.java | 18 + src/test/java/com/percero/example/Block.java | 86 +++++ src/test/java/com/percero/example/Email.java | 190 +++++++++++ .../percero/example/ExampleAccountHelper.java | 21 ++ .../example/ExampleChangeWatcherFactory.java | 10 + .../com/percero/example/ExampleManifest.java | 54 +++ .../percero/example/ExampleProcessHelper.java | 8 + src/test/java/com/percero/example/Person.java | 235 +++++++++++++ .../java/com/percero/example/PersonRole.java | 180 ++++++++++ src/test/resources/google/client_secrets.json | 13 + src/test/resources/google/privatekey.p12 | Bin 0 -> 2572 bytes .../resources/properties/test/env.properties | 68 ++++ .../spring/update_table_processor.xml | 319 ++++++++++++++++++ src/test/sql/example_schema.sql | 0 21 files changed, 1592 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java create mode 100644 src/main/java/com/percero/agents/sync/jobs/UpdateTableRow.java create mode 100644 src/main/java/com/percero/agents/sync/jobs/UpdateTableRowType.java create mode 100644 src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java create mode 100644 src/test/java/com/percero/example/Block.java create mode 100644 src/test/java/com/percero/example/Email.java create mode 100644 src/test/java/com/percero/example/ExampleAccountHelper.java create mode 100644 src/test/java/com/percero/example/ExampleChangeWatcherFactory.java create mode 100644 src/test/java/com/percero/example/ExampleManifest.java create mode 100644 src/test/java/com/percero/example/ExampleProcessHelper.java create mode 100644 src/test/java/com/percero/example/Person.java create mode 100644 src/test/java/com/percero/example/PersonRole.java create mode 100644 src/test/resources/google/client_secrets.json create mode 100644 src/test/resources/google/privatekey.p12 create mode 100644 src/test/resources/properties/test/env.properties create mode 100644 src/test/resources/spring/update_table_processor.xml create mode 100644 src/test/sql/example_schema.sql diff --git a/pom.xml b/pom.xml index a67e2fe..f7fd561 100644 --- a/pom.xml +++ b/pom.xml @@ -293,6 +293,20 @@ + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.7 + 1.7 + + + + + com.springsource.repository.bundles.release @@ -315,4 +329,6 @@ http://maven.springframework.org/release + + \ No newline at end of file diff --git a/src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java b/src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java index abb1644..dfe3855 100644 --- a/src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java @@ -1,14 +1,5 @@ package com.percero.agents.sync.helpers; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.apache.log4j.Logger; -import org.codehaus.jackson.map.ObjectMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.services.IPushSyncHelper; import com.percero.agents.sync.services.ISyncAgentService; @@ -16,6 +7,14 @@ import com.percero.agents.sync.vo.PushDeleteResponse; import com.percero.agents.sync.vo.RemovedClassIDPair; import com.percero.framework.vo.IPerceroObject; +import org.apache.log4j.Logger; +import org.codehaus.jackson.map.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; @Component public class PostDeleteHelper { @@ -63,25 +62,27 @@ public void postDeleteObject(IPerceroObject theObject, String pusherUserId, Stri log.debug("PostDeleteHelper for " + theObject.toString() + " from clientId " + (pusherClientId == null ? "NULL" : pusherClientId)); ClassIDPair pair = new ClassIDPair(theObject.getID(), theObject.getClass().getCanonicalName()); - + postDeleteObject(pair, pusherUserId, pusherClientId, pushToUser); + } + + public void postDeleteObject(ClassIDPair pair, String pusherUserId, String pusherClientId, boolean pushToUser) throws Exception { // Remove all UpdateJournals for the objects. accessManager.removeUpdateJournalsByObject(pair); // Notify interested users that this object has been deleted. RemovedClassIDPair removedPair = new RemovedClassIDPair(); - removedPair.setClassName(theObject.getClass().getName()); - removedPair.setID(theObject.getID()); + removedPair.setClassName(pair.getClassName()); + removedPair.setID(pair.getID()); + + List clientIds = accessManager.getObjectAccessJournals(pair.getClassName(), pair.getID()); - List clientIds = accessManager.getObjectAccessJournals(theObject - .getClass().getName(), theObject.getID()); - // Now remove the AccessJournals for this Object. accessManager.removeAccessJournalsByObject(pair); // Now remove the ObjectModJournals for this Object. accessManager.removeObjectModJournalsByObject(pair); // Now remove the HistoricalObjects for this Object. accessManager.removeHistoricalObjectsByObject(pair); - + // Now run past the ChangeWatcher. accessManager.checkChangeWatchers(pair, null, null); // Remove ChangeWatchers associated with this object. diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java index 747b09b..8ef0bd9 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java @@ -22,20 +22,32 @@ public class UpdateTableConnectionFactory { private static Logger logger = Logger.getLogger(UpdateTableConnectionFactory.class); @Autowired - @Value("pf{updateTable.driverClassName:com.mysql.jdbc.Driver") + @Value("pf{updateTable.driverClassName:com.mysql.jdbc.Driver}") private String driverClassName; + public void setDriverClassName(String val){ + this.driverClassName = val; + } @Autowired - @Value("pf{updateTable.username") + @Value("pf{updateTable.username}") private String username; + public void setUsername(String val){ + this.username = val; + } @Autowired - @Value("pf{updateTable.username") + @Value("pf{updateTable.username}") private String password; + public void setPassword(String val){ + this.password = val; + } @Autowired - @Value("pf{updateTable.jdbcUrl:jdbc:mysql://localhost/db") + @Value("pf{updateTable.jdbcUrl:jdbc:mysql://localhost/db}") private String jdbcUrl; + public void setJdbcUrl(String val){ + this.jdbcUrl = val; + } private ComboPooledDataSource cpds; @PostConstruct @@ -47,10 +59,9 @@ public void init() throws PropertyVetoException{ cpds.setUser(username); cpds.setPassword(password); -// the settings below are optional -- c3p0 can work with defaults + // the settings below are optional -- c3p0 can work with defaults cpds.setMinPoolSize(5); cpds.setAcquireIncrement(5); - cpds.setMaxPoolSize(20); }catch(PropertyVetoException pve){ logger.error(pve.getMessage(), pve); @@ -66,23 +77,4 @@ public Connection getConnection() throws SQLException{ throw e; } } - - public static void main(String[] args) throws Exception{ - UpdateTableConnectionFactory cf = new UpdateTableConnectionFactory(); - cf.driverClassName = "com.mysql.jdbc.Driver"; - cf.jdbcUrl = "jdbc:mysql://localhost/test"; - cf.username = "root"; - cf.password = "root"; - cf.init(); - - Connection c = cf.getConnection(); - Statement stmt = c.createStatement(); - - - ResultSet rs = stmt.executeQuery("SELECT * FROM Account"); - while(rs.next()) { - logger.info("ID: " + rs.getInt("ID")); - logger.info("markedForRemoval: "+ rs.getDate("markedForRemoval")); - } - } } diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java index 65e5e5e..31ead1b 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java @@ -1,6 +1,8 @@ package com.percero.agents.sync.jobs; import com.mchange.v2.c3p0.ComboPooledDataSource; +import com.percero.agents.sync.helpers.PostDeleteHelper; +import com.percero.framework.bl.IManifest; import org.apache.log4j.Logger; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -27,6 +29,12 @@ public void setTableNames(String val){ @Autowired UpdateTableConnectionFactory connectionFactory; + @Autowired + IManifest manifest; + + @Autowired + PostDeleteHelper postDeleteHelper; + /** * Run every minute */ @@ -34,7 +42,7 @@ public void setTableNames(String val){ public void pollUpdateTables(){ logger.info("Polling Update Tables..."); for(String tableName : tableNames){ - UpdateTableProcessor processor = new UpdateTableProcessor(tableName, connectionFactory); + UpdateTableProcessor processor = new UpdateTableProcessor(tableName, connectionFactory, manifest, postDeleteHelper); ProcessorResult result = processor.process(); if(result.isSuccess()){ logger.debug("Update table processor ("+tableName+") finished successfully. Total rows ("+result.getTotal()+")"); diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java new file mode 100644 index 0000000..e3e428a --- /dev/null +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java @@ -0,0 +1,257 @@ +package com.percero.agents.sync.jobs; + +import com.percero.agents.sync.helpers.PostDeleteHelper; +import com.percero.framework.bl.IManifest; +import org.apache.log4j.Logger; +import org.joda.time.DateTime; + +import javax.persistence.Table; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Date; +import java.util.Random; + +/** + * Responsible for querying an update table and processing the rows + * Created by Jonathan Samples on 8/31/15. + */ +public class UpdateTableProcessor { + + private static Logger logger = Logger.getLogger(UpdateTableProcessor.class); + + private static final int EXPIRATION_TIME = 1000*60*30; // 30 minutes + private String tableName; + private UpdateTableConnectionFactory connectionFactory; + private PostDeleteHelper postDeleteHelper; + private IManifest manifest; + + + public UpdateTableProcessor(String tableName, + UpdateTableConnectionFactory connectionFactory, + IManifest manifest, + PostDeleteHelper postDeleteHelper){ + this.tableName = tableName; + this.connectionFactory = connectionFactory; + this.postDeleteHelper = postDeleteHelper; + this.manifest = manifest; + } + + /** + * Update table schema looks like this + * + * `ID` int(11) NOT NULL AUTO_INCREMENT, + * `tableName` varchar(255) DEFAULT NULL, + * `rowID` varchar(255) DEFAULT NULL, + * `type` enum('INSERT','UPDATE','DELETE') NOT NULL DEFAULT 'UPDATE', + * `lockID` int(11) DEFAULT NULL, + * `lockDate` datetime DEFAULT NULL, + * `timestamp` timestamp DEFAULT CURRENT_TIMESTAMP + * + * @return + */ + public ProcessorResult process(){ + ProcessorResult result = new ProcessorResult(); + + while(true) { + UpdateTableRow row = getRow(); + if(row == null) break; + + if(processRow(row)) { + result.addResult(row.getType().toString()); + deleteRow(row); + } + else { + result.addResult(row.getType().toString(), false, ""); + } + + } + + return result; + } + + private boolean processRow(UpdateTableRow row){ + boolean result = true; + + if(row.getRowId() != null) + switch (row.getType()){ + case DELETE: + result = processDeleteSingle(row); + break; + case UPDATE: + result = processUpdateSingle(row); + break; + case INSERT: + result = processInsertSingle(row); + break; + default: // Don't know how to process + result = true; + break; + } + else + switch (row.getType()){ + case DELETE: + result = processDeleteTable(row); + break; + case UPDATE: + result = processUpdateTable(row); + break; + case INSERT: + result = processInsertTable(row); + break; + default: // Don't know how to process + result = true; + break; + } + + return result; + } + + /** + * Process a single record delete + * @param row + * @return + */ + private boolean processDeleteSingle(UpdateTableRow row){ + + return true; + } + + /** + * Process a single record update + * @param row + * @return + */ + private boolean processUpdateSingle(UpdateTableRow row){ + return true; + } + + /** + * process a single record insert + * @param row + * @return + */ + private boolean processInsertSingle(UpdateTableRow row){ + return true; + } + + /** + * process a whole table with deletes + * @param row + * @return + */ + private boolean processDeleteTable(UpdateTableRow row){ + return true; + } + + /** + * Process a whole table with updates + * @param row + * @return + */ + private boolean processUpdateTable(UpdateTableRow row){ + return true; + } + + /** + * Process a whole table with inserts + * @param row + * @return + */ + private boolean processInsertTable(UpdateTableRow row){ + return true; + } + + /** + * Pulls a row off the update table and locks it so that other + * processors don't duplicate the work + * @return + */ + private UpdateTableRow getRow(){ + UpdateTableRow row = null; + + try(Connection conn = connectionFactory.getConnection()){ + + Random rand = new Random(); + + int lockId = rand.nextInt(); + long now = System.currentTimeMillis(); + + DateTime expireThreshold = new DateTime(now - EXPIRATION_TIME); + + /** + * First try to lock a row + */ + String sql = "update :tableName set lockId=:lockId, lockDate=NOW() where lockId is null or lockDate < :expireThreshold limit 1"; + sql.replace(":tableName", tableName); + sql.replace(":lockId", lockId+""); + sql.replace(":expireThreshold", expireThreshold.toString("Y-MM-dd HH:mm:ss")); + + Statement statement; + + statement = conn.createStatement(); + int numUpdated = statement.executeUpdate(sql); + + // Found a row to process + if(numUpdated > 0){ + sql = "select * from :tableName where lockId=:lockId limit 1"; + sql.replace(":tableName", tableName); + sql.replace(":lockId", lockId+""); + statement = conn.createStatement(); + ResultSet rs = statement.executeQuery(sql); + + // If got a row back + if(rs.next()){ + row = UpdateTableRow.fromResultSet(rs); + rs.close(); + } + else{ + logger.warn("Locked a row but couldn't retrieve"); + } + } + + } catch(SQLException e){ + logger.warn(e.getMessage(), e); + } + + return row; + } + + /** + * Deletes the row + * @param row + */ + private void deleteRow(UpdateTableRow row){ + try(Connection conn = connectionFactory.getConnection()){ + String sql = "delete from :tableName where ID=:ID"; + sql.replace(":ID", row.getID()+""); + Statement statement = conn.createStatement(); + int numUpdated = statement.executeUpdate(sql); + if(numUpdated != 1){ + logger.warn("Expected to delete 1, instead "+numUpdated); + } + }catch(SQLException e){ + logger.warn(e.getMessage(), e); + } + } + + public Class getClassForTableName(String tableName){ + Class result = null; + for(Class c : manifest.getClassList()){ + Table table = (Table) c.getAnnotation(Table.class); + if(tableName.equals(table.name())) { + result = c; + break; + } + } + + return result; + } + + public static void main(String[] args){ + DateTime time = new DateTime(); + logger.info(time.toString("Y-MM-dd HH:mm:ss")); + } + +} diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableRow.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableRow.java new file mode 100644 index 0000000..aa44712 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableRow.java @@ -0,0 +1,66 @@ +package com.percero.agents.sync.jobs; + +import org.apache.log4j.Logger; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Date; + +/** + * Class to represent a row from the an update table + * Created by jonnysamps on 9/3/15. + */ +public class UpdateTableRow { + + private static Logger logger = Logger.getLogger(UpdateTableRow.class); + + public int ID; + public String tableName; + public String rowId; + public int lockId; + public Date lockDate; + public Date timestamp; + public UpdateTableRowType type; + + public Date getTimestamp() { + return timestamp; + } + + public int getID() { + return ID; + } + + public String getTableName() { + return tableName; + } + + public String getRowId() { + return rowId; + } + + public int getLockId() { + return lockId; + } + + public Date getLockDate() { + return lockDate; + } + + public UpdateTableRowType getType() { + return type; + } + + + public static UpdateTableRow fromResultSet(ResultSet resultSet) throws SQLException{ + UpdateTableRow row = new UpdateTableRow(); + row.ID = resultSet.getInt("ID"); + row.tableName = resultSet.getString("tableName"); + row.rowId = resultSet.getString("rowId"); + row.lockId = resultSet.getInt("lockId"); + row.lockDate = resultSet.getDate("lockDate"); + row.type = UpdateTableRowType.valueOf(resultSet.getString("type")); + row.timestamp = resultSet.getDate("timestamp"); + + return row; + } +} diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableRowType.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableRowType.java new file mode 100644 index 0000000..e2318a8 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableRowType.java @@ -0,0 +1,8 @@ +package com.percero.agents.sync.jobs; + +/** + * Created by jonnysamps on 9/3/15. + */ +public enum UpdateTableRowType { + UPDATE, INSERT, DELETE +} diff --git a/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java b/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java new file mode 100644 index 0000000..3f25143 --- /dev/null +++ b/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java @@ -0,0 +1,18 @@ +package com.percero.agents.sync.jobs; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * Created by Jonathan Samples on 9/4/15. + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:spring/update_table_processor.xml" }) +public class UpdateTableProcessorTest { + @Test + public void test(){ + System.out.println("A Test ran"); + } +} diff --git a/src/test/java/com/percero/example/Block.java b/src/test/java/com/percero/example/Block.java new file mode 100644 index 0000000..925bcbe --- /dev/null +++ b/src/test/java/com/percero/example/Block.java @@ -0,0 +1,86 @@ +package com.percero.example; + +import com.google.gson.JsonObject; +import com.percero.agents.sync.metadata.annotations.Externalize; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.serial.JsonUtils; +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import java.io.IOException; +import java.io.Serializable; + +@Entity +public class Block extends BaseDataObject implements Serializable{ + + ////////////////////////////////////////////////////// + // Properties + ////////////////////////////////////////////////////// + @Id + @Externalize + @Column(unique=true,name="ID") + private String ID; + @JsonProperty(value="ID") + public String getID() { + return this.ID; + } + @JsonProperty(value="ID") + public void setID(String value) { + this.ID = value; + } + + @Column + @Externalize + private String color; + public String getColor() { + return this.color; + } + public void setColor(String value) + { + this.color = value; + } + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + String objectJson = super.retrieveJson(objectMapper); + + // Properties + objectJson += ",\"color\":"; + if (getColor() == null) + objectJson += "null"; + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson += objectMapper.writeValueAsString(getColor()); + } catch (JsonGenerationException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (IOException e) { + objectJson += "null"; + e.printStackTrace(); + } + } + + return objectJson; + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + setColor(JsonUtils.getJsonString(jsonObject, "color")); + } +} diff --git a/src/test/java/com/percero/example/Email.java b/src/test/java/com/percero/example/Email.java new file mode 100644 index 0000000..84ca055 --- /dev/null +++ b/src/test/java/com/percero/example/Email.java @@ -0,0 +1,190 @@ +package com.percero.example; + +import com.google.gson.JsonObject; +import com.percero.agents.auth.vo.IUserIdentifier; +import com.percero.agents.sync.metadata.annotations.*; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.serial.BDODeserializer; +import com.percero.serial.BDOSerializer; +import com.percero.serial.JsonUtils; +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.annotate.JsonDeserialize; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +import javax.persistence.*; +import java.io.IOException; +import java.io.Serializable; +import java.util.Date; + + +@EntityInterface(interfaceClass=IUserIdentifier.class) +@Entity +public class Email extends BaseDataObject implements Serializable, IUserIdentifier +{ + ////////////////////////////////////////////////////// + // VERSION + ////////////////////////////////////////////////////// + @Override + public String classVersion() { + return "0.0.0"; + } + + + ////////////////////////////////////////////////////// + // ID + ////////////////////////////////////////////////////// + @Id + @Externalize + @Column(unique=true,name="ID") + private String ID; + @JsonProperty(value="ID") + public String getID() { + return this.ID; + } + @JsonProperty(value="ID") + public void setID(String value) { + this.ID = value; + } + + ////////////////////////////////////////////////////// + // Properties + ////////////////////////////////////////////////////// + @Column + @Externalize + private Date dateCreated; + public Date getDateCreated() { + return this.dateCreated; + } + public void setDateCreated(Date value) + { + this.dateCreated = value; + } + + @Column + @Externalize + private Date dateModified; + public Date getDateModified() { + return this.dateModified; + } + public void setDateModified(Date value) + { + this.dateModified = value; + } + + @Column + @PropertyInterface(entityInterfaceClass=IUserIdentifier.class, propertyName="userIdentifier", + params={@PropertyInterfaceParam(name="paradigm", value="email")} + ) + @Externalize + private String value; + public String getValue() { + return this.value; + } + public void setValue(String value) + { + this.value = value; + } + + + ////////////////////////////////////////////////////// + // Source Relationships + ////////////////////////////////////////////////////// + @RelationshipInterface(entityInterfaceClass=IUserIdentifier.class, sourceVarName="userAnchor") + @Externalize + @JsonSerialize(using=BDOSerializer.class) + @JsonDeserialize(using=BDODeserializer.class) + @JoinColumn(name="user_ID") + @org.hibernate.annotations.ForeignKey(name="FK_User_user_TO_Email") + @ManyToOne(fetch=FetchType.LAZY, optional=false) + private Person person; + public Person getPerson() { + return this.person; + } + public void setUser(Person value) { + this.person = value; + } + + ////////////////////////////////////////////////////// + // Target Relationships + ////////////////////////////////////////////////////// + + + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + String objectJson = super.retrieveJson(objectMapper); + + // Properties + objectJson += ",\"dateCreated\":"; + if (getDateCreated() == null) + objectJson += "null"; + else { + objectJson += getDateCreated().getTime(); + } + + objectJson += ",\"dateModified\":"; + if (getDateModified() == null) + objectJson += "null"; + else { + objectJson += getDateModified().getTime(); + } + + objectJson += ",\"value\":"; + if (getValue() == null) + objectJson += "null"; + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson += objectMapper.writeValueAsString(getValue()); + } catch (JsonGenerationException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (IOException e) { + objectJson += "null"; + e.printStackTrace(); + } + } + + // Source Relationships + objectJson += ",\"person\":"; + if (getPerson() == null) + objectJson += "null"; + else { + try { + objectJson += ((BaseDataObject) getPerson()).toEmbeddedJson(); + } catch(Exception e) { + objectJson += "null"; + } + } + objectJson += ""; + + // Target Relationships + + return objectJson; + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + setDateCreated(JsonUtils.getJsonDate(jsonObject, "dateCreated")); + setDateModified(JsonUtils.getJsonDate(jsonObject, "dateModified")); + setValue(JsonUtils.getJsonString(jsonObject, "value")); + + // Source Relationships + this.person = JsonUtils.getJsonPerceroObject(jsonObject, "person"); + + // Target Relationships + } +} diff --git a/src/test/java/com/percero/example/ExampleAccountHelper.java b/src/test/java/com/percero/example/ExampleAccountHelper.java new file mode 100644 index 0000000..c8eb060 --- /dev/null +++ b/src/test/java/com/percero/example/ExampleAccountHelper.java @@ -0,0 +1,21 @@ +package com.percero.example; + +import com.percero.agents.auth.helpers.AccountHelper; +import com.percero.framework.bl.ManifestHelper; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +@Component +public class ExampleAccountHelper extends AccountHelper { + + private static final Logger log = Logger.getLogger(ExampleAccountHelper.class); + + public static final String ROLE_ADMIN = "ADMIN"; + public static final String ROLE_BASIC = "BASIC"; + + public ExampleAccountHelper() { + super(); + manifest = new ExampleManifest(); + ManifestHelper.setManifest(manifest); + } +} diff --git a/src/test/java/com/percero/example/ExampleChangeWatcherFactory.java b/src/test/java/com/percero/example/ExampleChangeWatcherFactory.java new file mode 100644 index 0000000..929d2d9 --- /dev/null +++ b/src/test/java/com/percero/example/ExampleChangeWatcherFactory.java @@ -0,0 +1,10 @@ +package com.percero.example; + +import com.percero.agents.sync.cw.ChangeWatcherHelperFactory; +import org.springframework.stereotype.Component; + + +@Component +public class ExampleChangeWatcherFactory extends ChangeWatcherHelperFactory { + +} \ No newline at end of file diff --git a/src/test/java/com/percero/example/ExampleManifest.java b/src/test/java/com/percero/example/ExampleManifest.java new file mode 100644 index 0000000..a9cf5b9 --- /dev/null +++ b/src/test/java/com/percero/example/ExampleManifest.java @@ -0,0 +1,54 @@ +package com.percero.example; + +import com.percero.framework.bl.IManifest; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by jonnysamps on 9/4/15. + */ +@Component +public class ExampleManifest implements IManifest { + private List classList = null; + public List getClassList() { + if (classList == null) { + classList = new ArrayList(); + // Register Classes here + classList.add(Person.class); + classList.add(PersonRole.class); + classList.add(Email.class); + classList.add(Block.class); + } + return classList; + } + + private List objectList = null; + public List getObjectList() { + if (objectList == null) { + objectList = new ArrayList(); + // Instantiate one of each model object + objectList.add(new Person()); + objectList.add(new PersonRole()); + objectList.add(new Email()); + objectList.add(new Block()); + } + return objectList; + } + + private Map uuidMap = null; + public Map getUuidMap() { + if (uuidMap == null) { + uuidMap = new HashMap(); + // Create UUID map for each model class + uuidMap.put("1", Person.class); + uuidMap.put("2", PersonRole.class); + uuidMap.put("3", Email.class); + uuidMap.put("4", Block.class); + } + return uuidMap; + } +} diff --git a/src/test/java/com/percero/example/ExampleProcessHelper.java b/src/test/java/com/percero/example/ExampleProcessHelper.java new file mode 100644 index 0000000..7318763 --- /dev/null +++ b/src/test/java/com/percero/example/ExampleProcessHelper.java @@ -0,0 +1,8 @@ +package com.percero.example; + +import com.percero.agents.sync.helpers.ProcessHelper; +import org.springframework.stereotype.Component; + +@Component +public class ExampleProcessHelper extends ProcessHelper { +} diff --git a/src/test/java/com/percero/example/Person.java b/src/test/java/com/percero/example/Person.java new file mode 100644 index 0000000..312be9d --- /dev/null +++ b/src/test/java/com/percero/example/Person.java @@ -0,0 +1,235 @@ +package com.percero.example; + +import com.google.gson.JsonObject; +import com.percero.agents.auth.vo.IUserAnchor; +import com.percero.agents.sync.metadata.annotations.EntityInterface; +import com.percero.agents.sync.metadata.annotations.Externalize; +import com.percero.agents.sync.metadata.annotations.PropertyInterface; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.serial.JsonUtils; +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; + +import javax.persistence.*; +import java.io.IOException; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Entity +@EntityInterface(interfaceClass=IUserAnchor.class) +public class Person extends BaseDataObject implements Serializable, IUserAnchor +{ + ////////////////////////////////////////////////////// + // VERSION + ////////////////////////////////////////////////////// + @Override + public String classVersion() { + return "0.0.0"; + } + + ////////////////////////////////////////////////////// + // Properties + ////////////////////////////////////////////////////// + @Id + @Externalize + @Column(unique=true,name="ID") + private String ID; + @JsonProperty(value="ID") + public String getID() { + return this.ID; + } + @JsonProperty(value="ID") + public void setID(String value) { + this.ID = value; + } + + @Column + @Externalize + private Date dateCreated; + public Date getDateCreated() { + return this.dateCreated; + } + public void setDateCreated(Date value) + { + this.dateCreated = value; + } + + @Column + @Externalize + private Date dateModified; + public Date getDateModified() { + return this.dateModified; + } + public void setDateModified(Date value) + { + this.dateModified = value; + } + + @Column + @PropertyInterface(entityInterfaceClass=IUserAnchor.class, propertyName="userId", params={}) + @Externalize + private String userId; + public String getUserId() { + return this.userId; + } + public void setUserId(String value) + { + this.userId = value; + } + + @Column + @PropertyInterface(entityInterfaceClass=IUserAnchor.class, propertyName="firstName", params={}) + @Externalize + private String firstName; + public String getFirstName() { + return this.firstName; + } + public void setFirstName(String value) + { + this.firstName = value; + } + + @Column + @PropertyInterface(entityInterfaceClass=IUserAnchor.class, propertyName="lastName",params={}) + @Externalize + private String lastName; + public String getLastName() { + return this.lastName; + } + public void setLastName(String value) + { + this.lastName = value; + } + + @Externalize + @OneToMany(fetch= FetchType.LAZY, targetEntity=PersonRole.class, mappedBy="person", cascade=javax.persistence.CascadeType.REMOVE) + private List personRoles; + public List getPersonRoles() { + return this.personRoles; + } + public void setPersonRoles(List value) { + this.personRoles = value; + } + + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + String objectJson = super.retrieveJson(objectMapper); + + // Properties + objectJson += ",\"dateCreated\":"; + if (getDateCreated() == null) + objectJson += "null"; + else { + objectJson += getDateCreated().getTime(); + } + + objectJson += ",\"dateModified\":"; + if (getDateModified() == null) + objectJson += "null"; + else { + objectJson += getDateModified().getTime(); + } + + objectJson += ",\"userId\":"; + if (getUserId() == null) + objectJson += "null"; + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson += objectMapper.writeValueAsString(getUserId()); + } catch (JsonGenerationException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (IOException e) { + objectJson += "null"; + e.printStackTrace(); + } + } + + objectJson += ",\"firstName\":"; + if (getFirstName() == null) + objectJson += "null"; + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson += objectMapper.writeValueAsString(getFirstName()); + } catch (JsonGenerationException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (IOException e) { + objectJson += "null"; + e.printStackTrace(); + } + } + + objectJson += ",\"lastName\":"; + if (getLastName() == null) + objectJson += "null"; + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson += objectMapper.writeValueAsString(getLastName()); + } catch (JsonGenerationException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (IOException e) { + objectJson += "null"; + e.printStackTrace(); + } + } + + objectJson += ",\"personRoles\":["; + if (getPersonRoles() != null) { + int personRolesCounter = 0; + for(PersonRole nextPersonRoles : getPersonRoles()) { + if (personRolesCounter > 0) + objectJson += ","; + try { + objectJson += nextPersonRoles.toEmbeddedJson(); + personRolesCounter++; + } catch(Exception e) { + // Do nothing. + } + } + } + + objectJson += "]"; + + + return objectJson; + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + setDateCreated(JsonUtils.getJsonDate(jsonObject, "dateCreated")); + setDateModified(JsonUtils.getJsonDate(jsonObject, "dateModified")); + setUserId(JsonUtils.getJsonString(jsonObject, "userId")); + setFirstName(JsonUtils.getJsonString(jsonObject, "firstName")); + setLastName(com.percero.serial.JsonUtils.getJsonString(jsonObject, "lastName")); + + this.personRoles = (List) JsonUtils.getJsonListPerceroObject(jsonObject, "personRoles"); + } + +} diff --git a/src/test/java/com/percero/example/PersonRole.java b/src/test/java/com/percero/example/PersonRole.java new file mode 100644 index 0000000..739b8e2 --- /dev/null +++ b/src/test/java/com/percero/example/PersonRole.java @@ -0,0 +1,180 @@ +package com.percero.example; + +import com.google.gson.JsonObject; +import com.percero.agents.auth.vo.IUserRole; +import com.percero.agents.sync.metadata.annotations.EntityInterface; +import com.percero.agents.sync.metadata.annotations.Externalize; +import com.percero.agents.sync.metadata.annotations.PropertyInterface; +import com.percero.agents.sync.metadata.annotations.RelationshipInterface; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.serial.JsonUtils; +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; + +import javax.persistence.*; +import java.io.IOException; +import java.io.Serializable; +import java.util.Date; + +@EntityInterface(interfaceClass=IUserRole.class) +@Entity +public class PersonRole extends BaseDataObject implements Serializable, IUserRole +{ + ////////////////////////////////////////////////////// + // VERSION + ////////////////////////////////////////////////////// + @Override + public String classVersion() { + return "0.0.0"; + } + + + ////////////////////////////////////////////////////// + // ID + ////////////////////////////////////////////////////// + @Id + @Externalize + @Column(unique=true,name="ID") + private String ID; + @JsonProperty(value="ID") + public String getID() { + return this.ID; + } + @JsonProperty(value="ID") + public void setID(String value) { + this.ID = value; + } + + ////////////////////////////////////////////////////// + // Properties + ////////////////////////////////////////////////////// + @Column + @Externalize + private Date dateCreated; + public Date getDateCreated() { + return this.dateCreated; + } + public void setDateCreated(Date value) + { + this.dateCreated = value; + } + + @Column + @Externalize + private Date dateModified; + public Date getDateModified() { + return this.dateModified; + } + public void setDateModified(Date value) + { + this.dateModified = value; + } + + @Column + @PropertyInterface(entityInterfaceClass=IUserRole.class, propertyName="roleName",params={}) + @Externalize + private String roleName; + public String getRoleName() { + return this.roleName; + } + public void setRoleName(String value) + { + this.roleName = value; + } + + + ////////////////////////////////////////////////////// + // Source Relationships + ////////////////////////////////////////////////////// + @RelationshipInterface(entityInterfaceClass=IUserRole.class, sourceVarName="userAnchor") + @Externalize + @JoinColumn(name="person_ID") + @org.hibernate.annotations.ForeignKey(name="FK_User_user_TO_UserRole") + @ManyToOne(fetch=FetchType.LAZY, optional=false) + private Person person; + public Person getPerson() { + return this.person; + } + public void setPerson(Person value) { + this.person = value; + } + + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + String objectJson = super.retrieveJson(objectMapper); + + // Properties + objectJson += ",\"dateCreated\":"; + if (getDateCreated() == null) + objectJson += "null"; + else { + objectJson += getDateCreated().getTime(); + } + + objectJson += ",\"dateModified\":"; + if (getDateModified() == null) + objectJson += "null"; + else { + objectJson += getDateModified().getTime(); + } + + objectJson += ",\"roleName\":"; + if (getRoleName() == null) + objectJson += "null"; + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson += objectMapper.writeValueAsString(getRoleName()); + } catch (JsonGenerationException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (IOException e) { + objectJson += "null"; + e.printStackTrace(); + } + } + + // Source Relationships + objectJson += ",\"person\":"; + if (getPerson() == null) + objectJson += "null"; + else { + try { + objectJson += getPerson().toEmbeddedJson(); + } catch(Exception e) { + objectJson += "null"; + } + } + objectJson += ""; + + // Target Relationships + + return objectJson; + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + setDateCreated(JsonUtils.getJsonDate(jsonObject, "dateCreated")); + setDateModified(JsonUtils.getJsonDate(jsonObject, "dateModified")); + setRoleName(JsonUtils.getJsonString(jsonObject, "roleName")); + + // Source Relationships + this.person = JsonUtils.getJsonPerceroObject(jsonObject, "person"); + + // Target Relationships + } +} + diff --git a/src/test/resources/google/client_secrets.json b/src/test/resources/google/client_secrets.json new file mode 100644 index 0000000..36a97f9 --- /dev/null +++ b/src/test/resources/google/client_secrets.json @@ -0,0 +1,13 @@ +{ + "web": { + "client_id":"426306336879-m3ffk6mqt63pot5pg1kq52b7rmf2lnfo.apps.googleusercontent.com", + "auth_uri":"https://accounts.google.com/o/oauth2/auth", + "token_uri":"https://accounts.google.com/o/oauth2/token", + "auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs", + "client_email":"426306336879-m3ffk6mqt63pot5pg1kq52b7rmf2lnfo@developer.gserviceaccount.com", + "client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/426306336879-m3ffk6mqt63pot5pg1kq52b7rmf2lnfo%40developer.gserviceaccount.com", + "client_secret":"HPH9s_dgj1pLNn4VcB5ZFxre", + "redirect_uris":["https://localhost:8081/oauth2callback.html"], + "javascript_origins":["https://localhost:8081"] + } +} \ No newline at end of file diff --git a/src/test/resources/google/privatekey.p12 b/src/test/resources/google/privatekey.p12 new file mode 100644 index 0000000000000000000000000000000000000000..bbae0079c04df6ff8478e18069f778810e3b36f0 GIT binary patch literal 2572 zcmY+EX*3iH8^;GTW9->78P~Oq_0mj@eb2sT$sQ6jmbhgX2}8KZQkDi~%RbYHs2C~B zh(Y!wO4i9B%NSeqy63#_z32V#oadb1|NlH6e+Vo)gqev2fo1Civ&ko$Chu`Eu`-on z*_wb@HsUF+M_@s>{x1S~0kI(WQ|xj&4q%S|UU9NBF_&V2hX^c?fsh5W{|}!&7X}Kv zfO&q7JO-N!QEZ@i8x&nS5}`^rL%sSyGRv#vn&JHd1{GQDc4TGPD(*on5Bw=>Xw;|Ue z=cZ6RM+%1tHN|!Ls7p|9N1|6pL+*zLJWAD`$)1*;rJBq6ofC4^LXgd6mxB4&T_2;M zx3^jkTY>+jO2S+(L_8tj9Z^f^XbKPM)_!M;MXHd)2%gAVf-b+b@jmT*O4D%OmL&B|!N zhSns{d^qU?ed@YMP}xduUpIi3%aSSaif`ttmoj31*vh`P$P(Os+S_av@X2J_;@gRY zRcNnVbl(E5*lTebx>M_rq2dx3*J&)A+Uw1XzV!x26HFkSg#kaDr0H7$Vh9^}wO{TL zqwvq*{)+9m_StZdTrHsYITm>-CqI4Wv8KD|kKHbNjc<#}ER#Zw!N2R-L&wZ zEz1WH%ifMo{e{v@!{U8)3?+$-mYZ7{+?XGP>j|MGLwneVesAnod`&kXo`3SO?@^QC zv|bwAh#*faMt>4D2uky4z9hM+-Jq4!tp1*Dm#*l8oYhiu)@H3rgpj8Zq3GybAMM|7 zl+?8FaCJ(xXFdaM_0q>$CRw8*2#-XZC?(R{JeCW)z)q~ z;VA`R&yOs$)%dBu(3?qR+LRslntMsdj5^}zbncBlc`f5g&vibXlbZ3AH#&2MyCms4 z4^5AA2POUE3qTu7E$uVd_V|8khn;^hnV*Q^=_N?O_$lK`!!t>e&@NAe;*q#0)Uf_8 z&}C-6a-|qXb<}WQ31d$KnTDe5CQN4gaOci8>e#{A^vYk5GerUyW$^&7DJ*gs-ToFsH>w8 zDAiMkUi_!T3O?1U)F~2UW&)h9bN?nx|0i1T-=bC8P?mp>+yQR~{npT3#X@Fww)6R0 zwDDM$Ip_-CjKrVdrJ_oswRD%1#Bw2zVaWn`l9bt4z7K6^GqfRI?A?z>z~26-GTE_a zDRuz5OmlrOS`Y1N`~aV*h;O@uQp}f_kSp-eZBwE~!}zGn*K~9D{kDABY+fdM&TIvF zqeaA1u4Qjn_|z{w9%+Jqhh%F>+zpDgbWiuz?(;X8Y%Nw7P)3r!%@Uz+f`tLJmyRfB zUD_Rn3#UMK{hzxsM$8@-44xJx({!-5eLz<=rw)OE6`kDo!1^U8grLF!OXQu-2p{|YSvXDi*=Rv zO#p|E=nN;xy`E30wLF_ouYOXY=j|K?geA|p`6(mF6IKl*^09)mbc^s5O4@u)pd4(4oP-ApU@RIFTnAR2!iH^9Z$uY^_0`n!5TstDA5c9g*{#u*wP% zRQPMAiRM0^M#Fer+W^+*#YlbhjkHefle6JN9dHM#ku>X369F!*VHLW((H~1ZI6pA? zd$`EzXsO=|q3RNaKCZSX!lR%LGz7F3-E={hpcvSsqt*ULe5eCv3*0d_#z_aK5K z?^Ygq+_pQE!@JJKzVoN6L=C? z?La^F*!5a(ej*R!*Ala-0mmI}?$tW^Wr(!xoka&iut(!Bw-SxGqY$kzuaMN(MfAQ` zIH^{(8@AuA(D{*xq9XogmSNVSGxRY*FlTosh7i-b74y^WeM|~>sKanr>}9)Z-vw8T zg1Tw`hv?kM*C(l7iWoM1O$l+;l6^kWB@CLPCLOLS_%QYM!sRj2R==)YX%S_-?b*EF zgM;Cx2yKKof(;B(;AUYK1_6KqCz!mdc4{A7@A!!*Fi~iO2kB%26ad3qJxfLh3O%pf RkkV2poHdoO`SrIV{sSPC% + + + + + + + + + + + classpath:properties/test/env.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + hibernate.dialect=org.hibernate.dialect.MySQLDialect + hibernate.hbm2ddl.auto=update + + hibernate.show_sql=false + hibernate.format_sql=false + + hibernate.connection.aggressive_release=true + hibernate.jdbc.batch_size=20 + hibernate.connection.autocommit=false + hibernate.enable_lazy_load_no_trans=true + + + + + com.percero.amqp + com.percero.agents.auth.vo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + hibernate.dialect=org.hibernate.dialect.MySQLDialect + hibernate.hbm2ddl.auto=update + + hibernate.show_sql=false + hibernate.format_sql=false + + hibernate.connection.aggressive_release=true + hibernate.jdbc.batch_size=20 + hibernate.connection.autocommit=false + hibernate.connection.autoReconnect=true + hibernate.enable_lazy_load_no_trans=true + + + + + $pf{domain.packageToScan} + + + + + + + + + diff --git a/src/test/sql/example_schema.sql b/src/test/sql/example_schema.sql new file mode 100644 index 0000000..e69de29 From 6f3e57a8531598339e448eb1f1679a83ffb3c739 Mon Sep 17 00:00:00 2001 From: Jonathan Samples Date: Sat, 5 Sep 2015 22:51:30 -0700 Subject: [PATCH 09/20] Update table: individual record updates, inserts, deletes --- .../agents/sync/cache/CacheManager.java | 137 +++++++ .../agents/sync/helpers/PostDeleteHelper.java | 1 - .../jobs/UpdateTableConnectionFactory.java | 8 +- .../agents/sync/jobs/UpdateTablePoller.java | 33 +- .../sync/jobs/UpdateTableProcessor.java | 127 ++++-- .../jobs/UpdateTableProcessorFactory.java | 40 ++ .../agents/sync/services/IDataProvider.java | 1 + .../sync/services/RedisDataProvider.java | 5 + .../sync/services/SyncAgentDataProvider.java | 368 +++++++----------- src/main/resources/log4j.properties | 2 + .../spring/percero-spring-config.xml | 1 + .../sync/jobs/UpdateTableProcessorTest.java | 109 +++++- src/test/java/com/percero/example/Person.java | 1 + .../resources/properties/test/env.properties | 6 +- src/test/sql/example_schema.sql | 15 + 15 files changed, 557 insertions(+), 297 deletions(-) create mode 100644 src/main/java/com/percero/agents/sync/cache/CacheManager.java create mode 100644 src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java diff --git a/src/main/java/com/percero/agents/sync/cache/CacheManager.java b/src/main/java/com/percero/agents/sync/cache/CacheManager.java new file mode 100644 index 0000000..6d45b17 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/cache/CacheManager.java @@ -0,0 +1,137 @@ +package com.percero.agents.sync.cache; + +import com.percero.agents.sync.access.RedisKeyUtils; +import com.percero.agents.sync.datastore.RedisDataStore; +import com.percero.agents.sync.metadata.IMappedClassManager; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClassManagerFactory; +import com.percero.agents.sync.metadata.MappedField; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.agents.sync.vo.ClassIDPair; +import com.percero.framework.vo.IPerceroObject; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import sun.misc.Cache; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; + +/** + * Created by jonnysamps on 9/5/15. + */ +@Component +public class CacheManager { + + private static Logger logger = Logger.getLogger(CacheManager.class); + + @Autowired + RedisDataStore redisDataStore; + + @Autowired + Long cacheTimeout = Long.valueOf(60 * 60 * 24 * 14); // Two weeks + + public void updateCachedObject(IPerceroObject perceroObject, Map> changedFields){ + // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... + try { + if (cacheTimeout > 0) { + // TODO: Also need to update the caches of anything object that is related to this object. + String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); + if (redisDataStore.hasKey(key)) { + redisDataStore.setValue(key, ((BaseDataObject) perceroObject).toJson()); + } + + // Iterate through each changed object and reset the cache for that object. + if (changedFields != null) { +// Iterator>> itrChangedFieldEntrySet = changedFields.entrySet().iterator(); +// Set keysToDelete = new HashSet(); +// while (itrChangedFieldEntrySet.hasNext()) { +// Map.Entry> nextEntry = itrChangedFieldEntrySet.next(); +// ClassIDPair thePair = nextEntry.getKey(); +// if (!thePair.comparePerceroObject(perceroObject)) { +// String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); +// keysToDelete.add(nextKey); +// } +// } + Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); + Set keysToDelete = new HashSet(); + while (itrChangedFieldKeyset.hasNext()) { + ClassIDPair thePair = itrChangedFieldKeyset.next(); + if (!thePair.comparePerceroObject(perceroObject)) { + String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); + keysToDelete.add(nextKey); + } + } + + if (!keysToDelete.isEmpty()) { + redisDataStore.deleteKeys(keysToDelete); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } else { + // No changedFields? We should never get here? + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + Iterator itrToManyFields = mappedClass.toManyFields.iterator(); + while (itrToManyFields.hasNext()) { + MappedField nextMappedField = itrToManyFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject) fieldObject).getID()); + if (redisDataStore.hasKey(nextKey)) { + redisDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while (itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject) nextListObject).getID()); + if (redisDataStore.hasKey(nextKey)) { + redisDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + } + } + } + } + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + while (itrToOneFields.hasNext()) { + MappedField nextMappedField = itrToOneFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject) fieldObject).getID()); + if (redisDataStore.hasKey(nextKey)) { + redisDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while (itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject) nextListObject).getID()); + if (redisDataStore.hasKey(nextKey)) { + redisDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + } + } + } + } + } + } + } catch (Exception e){ + logger.warn(e.getMessage(), e); + } + } +} diff --git a/src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java b/src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java index dfe3855..f089aa4 100644 --- a/src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java @@ -106,7 +106,6 @@ protected void pushObjectDeleteJournals(Collection clientIds, String cla pushDeleteResponse = new PushDeleteResponse(); pushDeleteResponse.setObjectList(new ArrayList()); -// pushDeleteResponse.setClientId(nextClientId); pushDeleteResponse.getObjectList().add(removedPair); pushDeleteResponse.setObjectJson(objectJson); diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java index 8ef0bd9..d5f5cd7 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java @@ -22,28 +22,28 @@ public class UpdateTableConnectionFactory { private static Logger logger = Logger.getLogger(UpdateTableConnectionFactory.class); @Autowired - @Value("pf{updateTable.driverClassName:com.mysql.jdbc.Driver}") + @Value("$pf{updateTable.driverClassName:com.mysql.jdbc.Driver}") private String driverClassName; public void setDriverClassName(String val){ this.driverClassName = val; } @Autowired - @Value("pf{updateTable.username}") + @Value("$pf{updateTable.username}") private String username; public void setUsername(String val){ this.username = val; } @Autowired - @Value("pf{updateTable.username}") + @Value("$pf{updateTable.username}") private String password; public void setPassword(String val){ this.password = val; } @Autowired - @Value("pf{updateTable.jdbcUrl:jdbc:mysql://localhost/db}") + @Value("$pf{updateTable.jdbcUrl:jdbc:mysql://localhost/db}") private String jdbcUrl; public void setJdbcUrl(String val){ this.jdbcUrl = val; diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java index 31ead1b..bdd4ea4 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java @@ -25,33 +25,28 @@ public void setTableNames(String val){ tableNames = val.split(","); } - @Autowired - UpdateTableConnectionFactory connectionFactory; + UpdateTableProcessorFactory updateTableProcessorFactory; - @Autowired - IManifest manifest; - - @Autowired - PostDeleteHelper postDeleteHelper; + public boolean enabled = true; /** * Run every minute */ - @Scheduled(fixedDelay=6000, initialDelay=6000) + @Scheduled(fixedDelay=10000, initialDelay=10000) public void pollUpdateTables(){ - logger.info("Polling Update Tables..."); - for(String tableName : tableNames){ - UpdateTableProcessor processor = new UpdateTableProcessor(tableName, connectionFactory, manifest, postDeleteHelper); - ProcessorResult result = processor.process(); - if(result.isSuccess()){ - logger.debug("Update table processor ("+tableName+") finished successfully. Total rows ("+result.getTotal()+")"); - } - else{ - logger.warn("Update table processor ("+tableName+") failed. Details:"); - logger.warn(result); + if(enabled) + for(String tableName : tableNames){ + UpdateTableProcessor processor = updateTableProcessorFactory.getProcessor(tableName); + ProcessorResult result = processor.process(); + if(result.isSuccess()){ + logger.debug("Update table processor ("+tableName+") finished successfully. Total rows ("+result.getTotal()+")"); + } + else{ + logger.warn("Update table processor ("+tableName+") failed. Details:"); + logger.warn(result); + } } - } } diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java index e3e428a..0bfd839 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java @@ -1,7 +1,16 @@ package com.percero.agents.sync.jobs; +import com.percero.agents.sync.cache.CacheManager; import com.percero.agents.sync.helpers.PostDeleteHelper; +import com.percero.agents.sync.helpers.PostPutHelper; +import com.percero.agents.sync.metadata.IMappedClassManager; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClassManagerFactory; +import com.percero.agents.sync.services.DataProviderManager; +import com.percero.agents.sync.services.IDataProvider; +import com.percero.agents.sync.vo.ClassIDPair; import com.percero.framework.bl.IManifest; +import com.percero.framework.vo.IPerceroObject; import org.apache.log4j.Logger; import org.joda.time.DateTime; @@ -14,7 +23,7 @@ import java.util.Random; /** - * Responsible for querying an update table and processing the rows + * Responsible for querying an update table and processing the rows. * Created by Jonathan Samples on 8/31/15. */ public class UpdateTableProcessor { @@ -25,17 +34,26 @@ public class UpdateTableProcessor { private String tableName; private UpdateTableConnectionFactory connectionFactory; private PostDeleteHelper postDeleteHelper; + private PostPutHelper postPutHelper; private IManifest manifest; - + private CacheManager cacheManager; + private DataProviderManager dataProviderManager; public UpdateTableProcessor(String tableName, UpdateTableConnectionFactory connectionFactory, IManifest manifest, - PostDeleteHelper postDeleteHelper){ + PostDeleteHelper postDeleteHelper, + PostPutHelper postPutHelper, + CacheManager cacheManager, + DataProviderManager dataProviderManager) + { this.tableName = tableName; this.connectionFactory = connectionFactory; this.postDeleteHelper = postDeleteHelper; + this.postPutHelper = postPutHelper; this.manifest = manifest; + this.cacheManager = cacheManager; + this.dataProviderManager= dataProviderManager; } /** @@ -58,12 +76,15 @@ public ProcessorResult process(){ UpdateTableRow row = getRow(); if(row == null) break; - if(processRow(row)) { - result.addResult(row.getType().toString()); - deleteRow(row); - } - else { - result.addResult(row.getType().toString(), false, ""); + try { + if (processRow(row)) { + result.addResult(row.getType().toString()); + deleteRow(row); + } else { + result.addResult(row.getType().toString(), false, ""); + } + }catch(Exception e){ + result.addResult(row.getType().toString(), false, e.getMessage()); } } @@ -71,7 +92,7 @@ public ProcessorResult process(){ return result; } - private boolean processRow(UpdateTableRow row){ + private boolean processRow(UpdateTableRow row) throws Exception{ boolean result = true; if(row.getRowId() != null) @@ -113,8 +134,9 @@ private boolean processRow(UpdateTableRow row){ * @param row * @return */ - private boolean processDeleteSingle(UpdateTableRow row){ - + private boolean processDeleteSingle(UpdateTableRow row) throws Exception{ + Class clazz = getClassForTableName(row.getTableName()); + postDeleteHelper.postDeleteObject(new ClassIDPair(row.getRowId(), clazz.getCanonicalName()), null, null, true); return true; } @@ -123,7 +145,18 @@ private boolean processDeleteSingle(UpdateTableRow row){ * @param row * @return */ - private boolean processUpdateSingle(UpdateTableRow row){ + private boolean processUpdateSingle(UpdateTableRow row) throws Exception{ + Class clazz = getClassForTableName(row.getTableName()); + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(clazz.getName()); + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); + ClassIDPair pair = new ClassIDPair(row.getRowId(), clazz.getCanonicalName()); + IPerceroObject object = dataProvider.systemGetById(pair, true); + + if(object != null){ + cacheManager.updateCachedObject(object, null); + postPutHelper.postPutObject(pair, null, null, true, null); + } return true; } @@ -132,7 +165,9 @@ private boolean processUpdateSingle(UpdateTableRow row){ * @param row * @return */ - private boolean processInsertSingle(UpdateTableRow row){ + private boolean processInsertSingle(UpdateTableRow row) throws Exception{ + Class clazz = getClassForTableName(row.getTableName()); + postPutHelper.postPutObject(new ClassIDPair(row.getRowId(), clazz.getCanonicalName()), null, null, true, null); return true; } @@ -168,10 +203,12 @@ private boolean processInsertTable(UpdateTableRow row){ * processors don't duplicate the work * @return */ - private UpdateTableRow getRow(){ + public UpdateTableRow getRow(){ UpdateTableRow row = null; - try(Connection conn = connectionFactory.getConnection()){ + try(Connection conn = connectionFactory.getConnection(); + Statement statement = conn.createStatement()) + { Random rand = new Random(); @@ -183,31 +220,28 @@ private UpdateTableRow getRow(){ /** * First try to lock a row */ - String sql = "update :tableName set lockId=:lockId, lockDate=NOW() where lockId is null or lockDate < :expireThreshold limit 1"; - sql.replace(":tableName", tableName); - sql.replace(":lockId", lockId+""); - sql.replace(":expireThreshold", expireThreshold.toString("Y-MM-dd HH:mm:ss")); - - Statement statement; + String sql = "update `:tableName` set lockID=:lockId, lockDate=NOW() " + + "where lockID is null or " + + "lockDate < ':expireThreshold' " + + "order by timestamp limit 1"; + sql = sql.replace(":tableName", tableName); + sql = sql.replace(":lockId", lockId+""); + sql = sql.replace(":expireThreshold", expireThreshold.toString("Y-MM-dd HH:mm:ss")); - statement = conn.createStatement(); int numUpdated = statement.executeUpdate(sql); // Found a row to process if(numUpdated > 0){ sql = "select * from :tableName where lockId=:lockId limit 1"; - sql.replace(":tableName", tableName); - sql.replace(":lockId", lockId+""); - statement = conn.createStatement(); - ResultSet rs = statement.executeQuery(sql); - - // If got a row back - if(rs.next()){ - row = UpdateTableRow.fromResultSet(rs); - rs.close(); - } - else{ - logger.warn("Locked a row but couldn't retrieve"); + sql = sql.replace(":tableName", tableName); + sql = sql.replace(":lockId", lockId+""); + + try(ResultSet rs = statement.executeQuery(sql)){ + // If got a row back + if(rs.next()) + row = UpdateTableRow.fromResultSet(rs); + else + logger.warn("Locked a row but couldn't retrieve"); } } @@ -225,7 +259,8 @@ private UpdateTableRow getRow(){ private void deleteRow(UpdateTableRow row){ try(Connection conn = connectionFactory.getConnection()){ String sql = "delete from :tableName where ID=:ID"; - sql.replace(":ID", row.getID()+""); + sql = sql.replace(":tableName", tableName); + sql = sql.replace(":ID", row.getID()+""); Statement statement = conn.createStatement(); int numUpdated = statement.executeUpdate(sql); if(numUpdated != 1){ @@ -238,20 +273,26 @@ private void deleteRow(UpdateTableRow row){ public Class getClassForTableName(String tableName){ Class result = null; + + // First look for the @Table annotation for(Class c : manifest.getClassList()){ Table table = (Table) c.getAnnotation(Table.class); - if(tableName.equals(table.name())) { + if(table != null && tableName.equals(table.name())) { result = c; break; } } - return result; - } + // If we didn't find that now look for the simple class name to match + if(result == null){ + for(Class c : manifest.getClassList()){ + if(tableName.equals(c.getSimpleName())) { + result = c; + break; + } + } + } - public static void main(String[] args){ - DateTime time = new DateTime(); - logger.info(time.toString("Y-MM-dd HH:mm:ss")); + return result; } - } diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java new file mode 100644 index 0000000..0c8e392 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java @@ -0,0 +1,40 @@ +package com.percero.agents.sync.jobs; + +import com.percero.agents.sync.cache.CacheManager; +import com.percero.agents.sync.helpers.PostDeleteHelper; +import com.percero.agents.sync.helpers.PostPutHelper; +import com.percero.agents.sync.services.DataProviderManager; +import com.percero.framework.bl.IManifest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Creates UpdateTableProcessor for the poller + * Created by jonnysamps on 9/4/15. + */ +@Component +public class UpdateTableProcessorFactory { + + @Autowired + UpdateTableConnectionFactory connectionFactory; + + @Autowired + IManifest manifest; + + @Autowired + PostDeleteHelper postDeleteHelper; + + @Autowired + PostPutHelper postPutHelper; + + @Autowired + CacheManager cacheManager; + + @Autowired + DataProviderManager dataProviderManager; + + public UpdateTableProcessor getProcessor(String tableName){ + return new UpdateTableProcessor(tableName, connectionFactory, manifest, + postDeleteHelper, postPutHelper, cacheManager, dataProviderManager); + } +} diff --git a/src/main/java/com/percero/agents/sync/services/IDataProvider.java b/src/main/java/com/percero/agents/sync/services/IDataProvider.java index ec8b82f..59d9ff2 100644 --- a/src/main/java/com/percero/agents/sync/services/IDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/IDataProvider.java @@ -25,6 +25,7 @@ public interface IDataProvider { public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String clientId); public IPerceroObject findById(ClassIDPair classIdPair, String userId); public T systemGetById(ClassIDPair classIdPair); + public T systemGetById(ClassIDPair classIdPair, boolean ignoreCache); public List findByIds(ClassIDPairs classIdPairs, String userId); public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId); public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId); diff --git a/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java b/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java index de3cbaa..651d0c3 100644 --- a/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java @@ -153,6 +153,11 @@ public IPerceroObject findById(ClassIDPair classIdPair, String userId) { return null;**/ } + @Override + public T systemGetById(ClassIDPair classIdPair, boolean ignoreCache) { + return null; + } + public IPerceroObject systemGetById(ClassIDPair classIdPair) { return null; } diff --git a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java b/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java index d933039..297e7d5 100644 --- a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java @@ -13,6 +13,7 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; +import com.percero.agents.sync.cache.CacheManager; import javassist.ClassPool; import javassist.CtClass; import javassist.CtField; @@ -66,22 +67,25 @@ public class SyncAgentDataProvider implements IDataProvider { // TODO: Better manage Hibernate Sessions (opening and closing). private static final Logger log = Logger.getLogger(SyncAgentDataProvider.class); - + public void initialize() { // Do nothing. } - + public String getName() { return "syncAgent"; } - + @Autowired RedisDataStore redisDataStore; - + @Autowired Long cacheTimeout = Long.valueOf(60 * 60 * 24 * 14); // Two weeks + @Autowired + CacheManager cacheManager; + @Autowired ObjectMapper safeObjectMapper; @@ -90,7 +94,7 @@ public String getName() { public void setAppSessionFactory(SessionFactory value) { appSessionFactory = value; } - + @SuppressWarnings({ "rawtypes", "unchecked" }) // TODO: @Transactional(readOnly=true) @@ -116,33 +120,33 @@ public PerceroList getAllByName(Object aName, Integer pageNumber * readAllQuery optimization * You can now define a readAllQuery on a class to imporove it's initial download time * for briefcase mode. - * + * * Only supports plain SQL for now */ if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); } - + log.debug("Using readAllQuery: "+aClassName); String selectQueryString = mappedClass.getReadAllQuery().getQuery(); - + String countQueryString = "select count(*) from ("+selectQueryString+") as U"; - + // Add the limit clause if (pageSize != null && pageNumber != null && pageSize.intValue() > 0) { int offset = pageSize.intValue() * pageNumber.intValue(); selectQueryString += " limit "+pageSize+" OFFSET "+offset; } - + query = s.createSQLQuery(selectQueryString).addEntity(theClass); countQuery = s.createSQLQuery(countQueryString); - + query.setParameter("userId", userId); countQuery.setParameter("userId", userId); } - else - if (theClass != null) { + else + if (theClass != null) { String countQueryString = ""; if (returnTotal) countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; @@ -187,8 +191,8 @@ public PerceroList getAllByName(Object aName, Integer pageNumber } if (query != null) { - - log.debug("Get ALL: "+aClassName); + + log.debug("Get ALL: "+aClassName); long t1 = new Date().getTime(); List list = query.list(); long t2 = new Date().getTime(); @@ -196,10 +200,10 @@ public PerceroList getAllByName(Object aName, Integer pageNumber PerceroList result = new PerceroList( (List) SyncHibernateUtils.cleanObject(list, s, userId) ); long t3 = new Date().getTime(); log.debug("Clean Time: "+(t3-t2)); - + result.setPageNumber(pageNumber); result.setPageSize(pageSize); - + if (returnTotal && pageSize != null && pageNumber != null && pageSize.intValue() > 0){ result.setTotalLength(((Number)countQuery.uniqueResult()).intValue()); log.debug("Total Obs: "+result.getTotalLength()); @@ -228,7 +232,7 @@ public Integer countAllByName(String aClassName, String userId) throws Exception try { Query countQuery = null; Class theClass = MappedClass.forName(aClassName); - + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); boolean isValidReadQuery = false; @@ -237,22 +241,22 @@ public Integer countAllByName(String aClassName, String userId) throws Exception isValidReadQuery = true; } } - + if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); } - + String selectQueryString = mappedClass.getReadAllQuery().getQuery(); - + String countQueryString = "select count(*) from ("+selectQueryString+") as U"; - + countQuery = s.createSQLQuery(countQueryString); countQuery.setParameter("userId", userId); } else if (theClass != null) { String countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; - + // If the Read Query/Filter uses the ID, then we need to check against each ID here. if (isValidReadQuery) { String queryFilterString = mappedClass.getReadQuery().getQuery(); @@ -265,7 +269,7 @@ else if (theClass != null) { } String countQueryFilterString = queryFilterString; countQueryFilterString = countQueryString + " WHERE (" + countQueryFilterString + ") > 0"; - + countQuery = s.createQuery(countQueryFilterString); mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); } @@ -274,7 +278,7 @@ else if (theClass != null) { countQuery = s.createQuery(countQueryString); } } - + if (countQuery != null) { // log.debug(countQuery.toString()); Integer result = ((Number)countQuery.uniqueResult()).intValue(); @@ -283,13 +287,13 @@ else if (theClass != null) { else { return null; } - + } catch (Exception e) { log.error("Unable to countAllByName", e); } finally { s.close(); } - + return 0; } @@ -316,33 +320,33 @@ public List runQuery(MappedClass mappedClass, String queryName, Object[] return null; } - + @SuppressWarnings({ "rawtypes", "unchecked" }) protected static List processQueryResults(String resultClassName, Query updateFilter, List updateFilterResult) throws Exception { String[] returnAliases = updateFilter.getReturnAliases(); Type[] returnTypes = updateFilter.getReturnTypes(); - + String[] fieldNames = new String[returnAliases.length]; String[] getMethodNames = new String[returnAliases.length]; String[] setMethodNames = new String[returnAliases.length]; Class[] fieldClasses = new Class[returnAliases.length]; - + Class clazz = null; ClassPool pool = null; CtClass evalClass = null; - + if (returnAliases.length > 1) { try { clazz = MappedClass.forName(resultClassName); } catch(Exception e) { // Class must not yet exist, so let's create it. } - + if (clazz == null) { pool = ClassPool.getDefault(); evalClass = pool.makeClass(resultClassName); } - + // Create a new Class based on the result set. for(int i = 0; i < returnAliases.length; i++) { Type nextType = returnTypes[i]; @@ -355,29 +359,29 @@ protected static List processQueryResults(String resultClassName, Query // Do nothing. Simply means the field name is not a Number. } String nextUpperFieldName = nextFieldName.substring(0, 1).toUpperCase() + nextFieldName.substring(1); - + fieldNames[i] = nextFieldName; getMethodNames[i] = "get" + nextUpperFieldName; setMethodNames[i] = "set" + nextUpperFieldName; fieldClasses[i] = nextType.getReturnedClass(); - + if (evalClass != null) { evalClass.addField(CtField.make("private " + fieldClasses[i].getCanonicalName() + " " + nextFieldName + ";", evalClass)); evalClass.addMethod(CtMethod.make("public void " + setMethodNames[i] + "(" + fieldClasses[i].getCanonicalName() + " value) {this." + nextFieldName + " = value;}", evalClass)); evalClass.addMethod(CtMethod.make("public " + nextTypeCanonicalName +" " + getMethodNames[i] + "() {return this." + nextFieldName + ";}", evalClass)); } } - + if (clazz == null && evalClass != null) { clazz = evalClass.toClass(); } } - + List results = new ArrayList(); // Now populate the newly created objects. for(Object nextResult : (List)updateFilterResult) { - + if (nextResult instanceof Object[]) { Object nextObject = clazz.newInstance(); for(int i = 0; i < returnAliases.length; i++) { @@ -385,15 +389,15 @@ protected static List processQueryResults(String resultClassName, Query Method setMethod = clazz.getDeclaredMethod(setMethodNames[i], formalParams); setMethod.invoke(nextObject, ((Object[])nextResult)[i]); } - + results.add(nextObject); } else results.add(nextResult); } - + return results; } - + //@SuppressWarnings({ "rawtypes", "unchecked" }) public IPerceroObject findById(ClassIDPair classIdPair, String userId) { boolean hasReadQuery = false; @@ -409,7 +413,7 @@ public IPerceroObject findById(ClassIDPair classIdPair, String userId) { try { boolean hasAccess = true; IPerceroObject result = systemGetById(classIdPair); - + if (result != null) { if (hasReadQuery) { if (s == null) @@ -443,21 +447,29 @@ public IPerceroObject findById(ClassIDPair classIdPair, String userId) { } return null; } - + @SuppressWarnings({ "rawtypes", "unchecked" }) public IPerceroObject systemGetById(ClassIDPair classIdPair) { + return systemGetById(classIdPair, false); + } + + public IPerceroObject systemGetById(ClassIDPair classIdPair, boolean ignoreCache) { Session s = null; try { Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); - + if (theClass != null) { - IPerceroObject result = retrieveFromRedisCache(classIdPair); + IPerceroObject result = null; + + if(!ignoreCache) + result = retrieveFromRedisCache(classIdPair); + String key = null; if (result == null) { s = appSessionFactory.openSession(); result = (IPerceroObject) s.get(theClass, classIdPair.getID()); - + // Now put the object in the cache. if (result != null) { key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); @@ -478,7 +490,7 @@ public IPerceroObject systemGetById(ClassIDPair classIdPair) { if (cacheTimeout > 0 && key != null) { redisDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); } - + return result; } else { return null; @@ -499,7 +511,7 @@ public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, if (theClass != null) { IPerceroObject result = retrieveFromRedisCache(classIdPair); String key = null; - + if (result == null) { if (s == null || !s.isOpen()) { s = appSessionFactory.openSession(); @@ -508,7 +520,7 @@ public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, sessionAlreadyOpen = true; } result = (IPerceroObject) s.get(theClass, classIdPair.getID()); - + // Now put the object in the cache. if (result != null) { key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); @@ -523,12 +535,12 @@ public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, else { key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); } - + // (Re)Set the expiration. if (cacheTimeout > 0 && key != null) { redisDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); } - + return result; } else { return null; @@ -545,7 +557,7 @@ public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, } return null; } - + @SuppressWarnings({ "rawtypes", "unchecked" }) private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Exception { IPerceroObject result = null; @@ -553,7 +565,7 @@ private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Ex IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); Class theClass = MappedClass.forName(classIdPair.getClassName()); MappedClass mc = mcm.getMappedClassByClassName(classIdPair.getClassName()); - + String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); String jsonObjectString = (String) redisDataStore.getValue(key); if (jsonObjectString != null) { @@ -579,20 +591,20 @@ private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Ex } } } - } - + } + return result; } @SuppressWarnings({ "rawtypes", "unchecked" }) private Map retrieveFromRedisCache(ClassIDPairs classIdPairs, Boolean pleaseSetTimeout) throws Exception { Map result = new HashMap(classIdPairs.getIds().size()); - + if (cacheTimeout > 0) { IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); Class theClass = MappedClass.forName(classIdPairs.getClassName()); MappedClass mc = mcm.getMappedClassByClassName(classIdPairs.getClassName()); - + Set keys = new HashSet(classIdPairs.getIds().size()); Iterator itrIds = classIdPairs.getIds().iterator(); while (itrIds.hasNext()) { @@ -612,7 +624,7 @@ private Map retrieveFromRedisCache(ClassIDPairs classIdP keys.add(nextKey); } } - + // String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); List jsonObjectStrings = redisDataStore.getValues(keys); Iterator itrJsonObjectStrings = jsonObjectStrings.iterator(); @@ -628,7 +640,7 @@ private Map retrieveFromRedisCache(ClassIDPairs classIdP IPerceroObject nextPerceroObject = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); result.put( nextPerceroObject.getID(), nextPerceroObject); } - + } // else { // // Check MappedClass' child classes. @@ -644,26 +656,26 @@ private Map retrieveFromRedisCache(ClassIDPairs classIdP // } // } } - + if (pleaseSetTimeout) { redisDataStore.expire(keys, cacheTimeout, TimeUnit.SECONDS); } } - + return result; } - + @SuppressWarnings({ "rawtypes" }) public Boolean getReadAccess(ClassIDPair classIdPair, String userId) { Session s = appSessionFactory.openSession(); try { Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); - + if (theClass != null) { IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); - + boolean hasAccess = (parent != null); - + if (hasAccess) { IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); @@ -677,7 +689,7 @@ public Boolean getReadAccess(ClassIDPair classIdPair, String userId) { } } } - + return hasAccess; } } catch (Exception e) { @@ -687,19 +699,19 @@ public Boolean getReadAccess(ClassIDPair classIdPair, String userId) { } return false; } - + @SuppressWarnings({ "rawtypes" }) public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { Session s = appSessionFactory.openSession(); try { Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); - + if (theClass != null) { IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); - + if (parent == null) return true; - + boolean hasAccess = true; IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); @@ -712,7 +724,7 @@ public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { hasAccess = false; } } - + return hasAccess; } } catch (Exception e) { @@ -722,11 +734,11 @@ public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { } return false; } - + @SuppressWarnings({ "rawtypes", "unchecked" }) public List findByIds(ClassIDPairs classIdPairs, String userId) { List result = null; - + boolean hasAccess = true; Class theClass = null; try { @@ -735,7 +747,7 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) log.error("Unable to get Class from class name " + classIdPairs.getClassName(), e2); return result; } - + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPairs.getClassName()); boolean isValidReadQuery = false; @@ -754,13 +766,13 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) try { // Attempt to get as many from the cache as possible... Map cachedObjects = retrieveFromRedisCache(classIdPairs, true); - + if (!cachedObjects.isEmpty()) { result = new ArrayList(cachedObjects.size()); List cachedResults = new ArrayList(cachedObjects.size()); cachedResults.addAll(cachedObjects.values()); idsSet.removeAll(cachedObjects.keySet()); - + // If there is a read query, we need to check each object through that query. if (isValidReadQuery) { Session s = null; @@ -768,7 +780,7 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) // Need to clean each result for the user. // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function s = appSessionFactory.openSession(); - + Iterator itrCachedResults = cachedResults.iterator(); while (itrCachedResults.hasNext()) { IPerceroObject nextCachedResult = itrCachedResults.next(); @@ -779,7 +791,7 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) if (readFilterResult == null || readFilterResult.intValue() <= 0) hasAccess = false; } - + if (hasAccess) { result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); } @@ -801,7 +813,7 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function // TODO: Maybe only clean relationships that are in mappedClass.readAccessRightsFieldReferences? s = appSessionFactory.openSession(); - + Iterator itrCachedResults = cachedResults.iterator(); while (itrCachedResults.hasNext()) { IPerceroObject nextCachedResult = itrCachedResults.next(); @@ -827,7 +839,7 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) // We errored out here, but we can still try and retrieve from the database. log.error("Error retrieving objects from redis cache, attempting to retrieve from database", e1); } - + // Now get the rest from the database. if (!idsSet.isEmpty()) { String queryString = "SELECT findByIdsResult FROM " + classIdPairs.getClassName() + " findByIdsResult WHERE findByIdsResult.ID IN (:idsSet)"; @@ -849,18 +861,18 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) queryFilterString = queryFilterString.replaceAll(":ID", "findByIdsResult.ID"); } queryFilterString = queryString + " AND (" + queryFilterString + ") > 0"; - + query = s.createQuery(queryFilterString); mappedClass.getReadQuery().setQueryParameters(query, null, userId); } else { query = s.createQuery(queryString); } - + query.setParameterList("idsSet", idsSet); List queryResult = query.list(); List cleanedDatabaseObjects = (List) SyncHibernateUtils.cleanObject(queryResult, s, userId); - + // Need to put results into cache. if (cacheTimeout > 0) { Map mapJsonObjectStrings = new HashMap(cleanedDatabaseObjects.size()); @@ -868,16 +880,16 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) while (itrDatabaseObjects.hasNext()) { IPerceroObject nextDatabaseObject = itrDatabaseObjects.next(); String nextCacheKey = RedisKeyUtils.classIdPair(nextDatabaseObject.getClass().getCanonicalName(), nextDatabaseObject.getID()); - + mapJsonObjectStrings.put(nextCacheKey, ((BaseDataObject)nextDatabaseObject).toJson()); } - + // Store the objects in redis. redisDataStore.setValues(mapJsonObjectStrings); // (Re)Set the expiration. redisDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); } - + if (result == null) { result = cleanedDatabaseObjects; } @@ -905,7 +917,7 @@ public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId) { Session s = appSessionFactory.openSession(); try { Class objectClass = theQueryObject.getClass(); - + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(objectClass.getName()); if (mappedClass != null) { @@ -994,7 +1006,7 @@ public List findByExample(IPerceroObject theQueryObject, List systemFindByExample(IPerceroObject theQueryObject, List excludeProperties) { Session s = appSessionFactory.openSession(); @@ -1004,23 +1016,23 @@ public List systemFindByExample(IPerceroObject theQueryObject, L BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); example.setPropertySelector(propertySelector); criteria.add(example); - + List result = criteria.list(); result = (List) SyncHibernateUtils.cleanObject(result, s); - + return (List) result; } catch (Exception e) { log.error("Unable to findByExample", e); } finally { s.close(); } - + return null; } @SuppressWarnings("unchecked") public List searchByExample(IPerceroObject theQueryObject, - List excludeProperties, String userId) { + List excludeProperties, String userId) { Session s = appSessionFactory.openSession(); try { Criteria criteria = s.createCriteria(theQueryObject.getClass()); @@ -1032,7 +1044,7 @@ public List searchByExample(IPerceroObject theQueryObject, List result = criteria.list(); result = (List) SyncHibernateUtils.cleanObject(result, s, userId); - + return result; } catch (Exception e) { log.error("Unable to searchByExample", e); @@ -1047,7 +1059,7 @@ public List searchByExample(IPerceroObject theQueryObject, public IPerceroObject systemCreateObject(IPerceroObject perceroObject) throws SyncException { Session s = appSessionFactory.openSession(); - + try { // Make sure object has an ID. IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); @@ -1064,14 +1076,14 @@ public IPerceroObject systemCreateObject(IPerceroObject perceroObject) return perceroObject; } } - + Transaction tx = s.beginTransaction(); tx.begin(); s.save(perceroObject); tx.commit(); - + s.refresh(perceroObject); - + perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObject, s); deepCleanObject(perceroObject, mappedClass, s, null); @@ -1128,26 +1140,26 @@ else if (fieldObject instanceof Collection) { } } } - + if (!keysToDelete.isEmpty()) { redisDataStore.deleteKeys(keysToDelete); // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); } } - + return perceroObject; } catch(PropertyValueException pve) { log.error("Error creating object", pve); - + SyncDataException sde = new SyncDataException(SyncDataException.MISSING_REQUIRED_FIELD, SyncDataException.MISSING_REQUIRED_FIELD_CODE, "Missing required field " + pve.getPropertyName()); sde.fieldName = pve.getPropertyName(); throw sde; } catch(Exception e) { log.error("Error creating object", e); - + SyncDataException sde = new SyncDataException(SyncDataException.CREATE_OBJECT_ERROR, SyncDataException.CREATE_OBJECT_ERROR_CODE); throw sde; } @@ -1157,7 +1169,7 @@ else if (fieldObject instanceof Collection) { } } } - + private void deepCleanObject(IPerceroObject perceroObject, MappedClass mappedClass, Session s, String userId) { if (!(perceroObject instanceof IRootObject)) { for(MappedField nextMappedField : mappedClass.externalizableFields) { @@ -1219,7 +1231,7 @@ public IPerceroObject createObject(IPerceroObject perceroObject, String userId) } } - + //////////////////////////////////////////////////// // PUT @@ -1278,113 +1290,15 @@ public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map 0) { - // TODO: Also need to update the caches of anything object that is related to this object. - String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); - if (redisDataStore.hasKey(key)) { - redisDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); - } - - // Iterate through each changed object and reset the cache for that object. - if (changedFields != null) { -// Iterator>> itrChangedFieldEntrySet = changedFields.entrySet().iterator(); -// Set keysToDelete = new HashSet(); -// while (itrChangedFieldEntrySet.hasNext()) { -// Map.Entry> nextEntry = itrChangedFieldEntrySet.next(); -// ClassIDPair thePair = nextEntry.getKey(); -// if (!thePair.comparePerceroObject(perceroObject)) { -// String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); -// keysToDelete.add(nextKey); -// } -// } - Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); - Set keysToDelete = new HashSet(); - while (itrChangedFieldKeyset.hasNext()) { - ClassIDPair thePair = itrChangedFieldKeyset.next(); - if (!thePair.comparePerceroObject(perceroObject)) { - String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); - keysToDelete.add(nextKey); - } - } - - if (!keysToDelete.isEmpty()) { - redisDataStore.deleteKeys(keysToDelete); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - else { - // No changedFields? We should never get here? - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - Iterator itrToManyFields = mappedClass.toManyFields.iterator(); - while(itrToManyFields.hasNext()) { - MappedField nextMappedField = itrToManyFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); - if (redisDataStore.hasKey(nextKey)) { - redisDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); - if (redisDataStore.hasKey(nextKey)) { - redisDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - } - } - } - } - Iterator itrToOneFields = mappedClass.toOneFields.iterator(); - while(itrToOneFields.hasNext()) { - MappedField nextMappedField = itrToOneFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); - if (redisDataStore.hasKey(nextKey)) { - redisDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); - if (redisDataStore.hasKey(nextKey)) { - redisDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - } - } - } - } - } - } + cacheManager.updateCachedObject(perceroObject, changedFields); return perceroObject; } catch (Exception e) { log.error("Error putting object", e); - + SyncDataException sde = new SyncDataException(SyncDataException.UPDATE_OBJECT_ERROR, SyncDataException.UPDATE_OBJECT_ERROR_CODE); throw sde; } finally { @@ -1392,7 +1306,7 @@ else if (fieldObject instanceof Collection) { } } - + //////////////////////////////////////////////////// // DELETE @@ -1405,7 +1319,7 @@ public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws Sy if (perceroObject == null) { return true; } - + boolean hasAccess = true; IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(theClassIdPair.getClassName()); @@ -1422,7 +1336,7 @@ public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws Sy if (hasAccess) { if (systemDeleteObject(perceroObject)) { return true; - } + } else { return true; } @@ -1450,7 +1364,7 @@ public Boolean systemDeleteObject(IPerceroObject perceroObject) throws SyncExcep // Make sure all associated objects are loaded. // Clean the object before deletion because otherwise it will fail. perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObjectToDelete, s); - + Transaction tx = s.beginTransaction(); tx.begin(); s.delete(perceroObjectToDelete); @@ -1509,7 +1423,7 @@ else if (fieldObject instanceof Collection) { } } } - + if (!keysToDelete.isEmpty()) { redisDataStore.deleteKeys(keysToDelete); // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? @@ -1520,7 +1434,7 @@ else if (fieldObject instanceof Collection) { result = true; } catch (Exception e) { log.error("Error deleting object", e); - + SyncDataException sde = new SyncDataException(SyncDataException.DELETE_OBJECT_ERROR, SyncDataException.DELETE_OBJECT_ERROR_CODE); throw sde; } finally { @@ -1550,14 +1464,14 @@ public Object cleanObject(Object object, Session s, String userId) { } } } - - + + @SuppressWarnings("rawtypes") public Map> getChangedMappedFields(IPerceroObject newObject) { Map> result = new HashMap>(); Collection baseObjectResult = null; ClassIDPair basePair = new ClassIDPair(newObject.getID(), newObject.getClass().getCanonicalName()); - + String className = newObject.getClass().getCanonicalName(); IPerceroObject oldObject = systemGetById(new ClassIDPair(newObject.getID(), className)); IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); @@ -1573,12 +1487,12 @@ public Map> getChangedMappedFields(IPercero result.put(basePair, baseObjectResult); } baseObjectResult.add(nextMappedField); - + // If this is a relationship field, then need to grab the old and new values. if (nextMappedField.getReverseMappedField() != null) { if (nextMappedField instanceof MappedFieldPerceroObject) { MappedFieldPerceroObject nextMappedFieldPerceroObject = (MappedFieldPerceroObject) nextMappedField; - + IPerceroObject oldReversePerceroObject = (IPerceroObject) nextMappedFieldPerceroObject.getGetter().invoke(oldObject); if (oldReversePerceroObject != null) { ClassIDPair oldReversePair = new ClassIDPair(oldReversePerceroObject.getID(), oldReversePerceroObject.getClass().getCanonicalName()); @@ -1589,7 +1503,7 @@ public Map> getChangedMappedFields(IPercero } oldReverseChangedFields.add(nextMappedField.getReverseMappedField()); } - + IPerceroObject newReversePerceroObject = (IPerceroObject) nextMappedFieldPerceroObject.getGetter().invoke(newObject); if (newReversePerceroObject != null) { ClassIDPair newReversePair = new ClassIDPair(newReversePerceroObject.getID(), newReversePerceroObject.getClass().getCanonicalName()); @@ -1603,22 +1517,22 @@ public Map> getChangedMappedFields(IPercero } else if (nextMappedField instanceof MappedFieldList) { MappedFieldList nextMappedFieldList = (MappedFieldList) nextMappedField; - + List oldReverseList = (List) nextMappedFieldList.getGetter().invoke(oldObject); if (oldReverseList == null) oldReverseList = new ArrayList(); - + List newReverseList = (List) nextMappedFieldList.getGetter().invoke(newObject); if (newReverseList == null) newReverseList = new ArrayList(); - + // Compare each item in the lists. Collection oldChangedList = retrieveObjectsNotInCollection(oldReverseList, newReverseList); Iterator itrOldChangedList = oldChangedList.iterator(); while (itrOldChangedList.hasNext()) { BaseDataObject nextOldChangedObject = (BaseDataObject) itrOldChangedList.next(); ClassIDPair nextOldReversePair = BaseDataObject.toClassIdPair(nextOldChangedObject); - + // Old object is not in new list, so add to list of changed fields. Collection changedFields = result.get(nextOldReversePair); if (changedFields == null) { @@ -1633,7 +1547,7 @@ else if (nextMappedField instanceof MappedFieldList) { while (itrNewChangedList.hasNext()) { BaseDataObject nextNewChangedObject = (BaseDataObject) itrNewChangedList.next(); ClassIDPair nextNewReversePair = BaseDataObject.toClassIdPair(nextNewChangedObject); - + // Old object is not in new list, so add to list of changed fields. Collection changedFields = result.get(nextNewReversePair); if (changedFields == null) { @@ -1650,10 +1564,10 @@ else if (nextMappedField instanceof MappedFieldList) { baseObjectResult.add(nextMappedField); } } - + return result; } - + @SuppressWarnings({ "rawtypes", "unchecked" }) private Collection retrieveObjectsNotInCollection(Collection baseList, Collection compareToList) { Collection result = new HashSet(); @@ -1665,24 +1579,24 @@ private Collection retrieveObjectsNotInCollection(Collection baseList, Collectio BaseDataObject nextBasePerceroObject = (BaseDataObject) itrBaseList.next(); ClassIDPair nextBasePair = BaseDataObject.toClassIdPair(nextBasePerceroObject); nextBasePerceroObject = (BaseDataObject) systemGetById(nextBasePair); - + itrCompareToList = compareToList.iterator(); matchFound = false; while (itrCompareToList.hasNext()) { BaseDataObject nextCompareToPerceroObject = (BaseDataObject) itrCompareToList.next(); nextCompareToPerceroObject = (BaseDataObject) systemGetById(BaseDataObject.toClassIdPair(nextCompareToPerceroObject)); - + if (nextBasePerceroObject.getClass() == nextCompareToPerceroObject.getClass() && nextBasePerceroObject.getID().equalsIgnoreCase(nextCompareToPerceroObject.getID())) { matchFound = true; break; } } - + if (!matchFound) { result.add(nextBasePerceroObject); } } - + return result; } } diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties index e55f929..6a6b6bf 100644 --- a/src/main/resources/log4j.properties +++ b/src/main/resources/log4j.properties @@ -1,5 +1,7 @@ log4j.rootLogger=info, stdout +log4j.category.com.percero.agents.sync.jobs=DEBUG + log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout diff --git a/src/main/resources/spring/percero-spring-config.xml b/src/main/resources/spring/percero-spring-config.xml index 6f3b4fb..d3a16c2 100644 --- a/src/main/resources/spring/percero-spring-config.xml +++ b/src/main/resources/spring/percero-spring-config.xml @@ -45,6 +45,7 @@ + diff --git a/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java b/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java index 3f25143..7d9a0bf 100644 --- a/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java +++ b/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java @@ -1,18 +1,123 @@ package com.percero.agents.sync.jobs; +import com.percero.example.Email; +import com.percero.example.Person; +import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; + /** * Created by Jonathan Samples on 9/4/15. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:spring/update_table_processor.xml" }) public class UpdateTableProcessorTest { + + @Autowired + UpdateTableProcessorFactory processorFactory; + @Autowired + UpdateTableConnectionFactory connectionFactory; + @Autowired + UpdateTablePoller poller; + + String tableName = "update_table"; + + @Before + public void before() throws Exception{ + // Disable the poller so it doesn't step on our toes + poller.enabled = false; + try(Connection connection = connectionFactory.getConnection(); + Statement statement = connection.createStatement()) + { + String sql = "delete from " + tableName; + statement.executeUpdate(sql); + + // Add some fixture data + statement.executeUpdate("insert into " + tableName + "(tableName, rowId, type) values " + + "('Email','1','UPDATE')," + + "('Person','1','INSERT')," + + "('Block','1','DELETE')"); + } + } + @Test - public void test(){ - System.out.println("A Test ran"); + public void test() throws Exception{ + try(Connection connection = connectionFactory.getConnection(); + Statement statement = connection.createStatement();) + { + String sql = "select count(*) as 'count' from " + tableName; + ResultSet resultSet = statement.executeQuery(sql); + Assert.assertTrue(resultSet.next()); + Assert.assertEquals(3, resultSet.getInt("count")); + } } + + @Test + public void getClassForTableName_NoTableAnnotation() throws Exception{ + UpdateTableProcessor processor = processorFactory.getProcessor(tableName); + Class clazz = processor.getClassForTableName("Email"); + Assert.assertEquals(Email.class, clazz); + } + + @Test + public void getClassForTableName_TableAnnotation() throws Exception{ + UpdateTableProcessor processor = processorFactory.getProcessor(tableName); + Class clazz = processor.getClassForTableName("Person"); + Assert.assertEquals(Person.class, clazz); + } + + @Test + public void getClassForTableName_NotFound() throws Exception{ + UpdateTableProcessor processor = processorFactory.getProcessor(tableName); + Class clazz = processor.getClassForTableName("NotAnEntity"); + Assert.assertNull(clazz); + } + + @Test + public void getRow() throws Exception { + UpdateTableProcessor processor = processorFactory.getProcessor(tableName); + UpdateTableRow row = processor.getRow(); + + Assert.assertNotNull(row); + Assert.assertNotNull(row.getLockId()); + Assert.assertNotNull(row.getLockDate()); + + String sql = "select * from "+tableName+" where ID="+row.getID(); + + try(Connection connection = connectionFactory.getConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery(sql)) + { + Assert.assertTrue(resultSet.next()); + Assert.assertNotNull(resultSet.getInt("lockID")); + Assert.assertNotNull(resultSet.getDate("lockDate")); + } + } + + + @Test + public void process() throws Exception { + UpdateTableProcessor processor = processorFactory.getProcessor(tableName); + ProcessorResult result = processor.process(); + Assert.assertEquals(3, result.getTotal()); + Assert.assertEquals(0, result.getNumFailed()); + Assert.assertTrue(result.isSuccess()); + try(Connection connection = connectionFactory.getConnection(); + Statement statement = connection.createStatement()) + { + String sql = "select count(*) as 'count' from " + tableName; + ResultSet resultSet = statement.executeQuery(sql); + Assert.assertTrue(resultSet.next()); + Assert.assertEquals(0, resultSet.getInt("count")); + } + } + } diff --git a/src/test/java/com/percero/example/Person.java b/src/test/java/com/percero/example/Person.java index 312be9d..fb1b7b0 100644 --- a/src/test/java/com/percero/example/Person.java +++ b/src/test/java/com/percero/example/Person.java @@ -19,6 +19,7 @@ import java.util.List; @Entity +@Table(name = "Person") @EntityInterface(interfaceClass=IUserAnchor.class) public class Person extends BaseDataObject implements Serializable, IUserAnchor { diff --git a/src/test/resources/properties/test/env.properties b/src/test/resources/properties/test/env.properties index 015ab17..2788f4e 100644 --- a/src/test/resources/properties/test/env.properties +++ b/src/test/resources/properties/test/env.properties @@ -65,4 +65,8 @@ pulseHttpAuth.hostPortAndContext=https://localhost:8900/auth pulseHttpAuth.trustAllCerts=true # Update Table -updateTable.tableNames=update_log \ No newline at end of file +updateTable.tableNames=update_log +updateTable.jdbcUrl=jdbc:mysql://localhost/as_example +updateTable.username=root +updateTable.password=root +updateTable.driverClassName=com.mysql.jdbc.Driver \ No newline at end of file diff --git a/src/test/sql/example_schema.sql b/src/test/sql/example_schema.sql index e69de29..c367916 100644 --- a/src/test/sql/example_schema.sql +++ b/src/test/sql/example_schema.sql @@ -0,0 +1,15 @@ +CREATE DATABASE IF NOT EXISTS as_example; + +DROP TABLE IF EXISTS `update_table`; +CREATE TABLE `update_table` ( + `ID` int(11) NOT NULL AUTO_INCREMENT, + `tableName` varchar(255) DEFAULT NULL, + `rowID` varchar(255) DEFAULT NULL, + `type` enum('INSERT','UPDATE','DELETE') NOT NULL DEFAULT 'UPDATE', + `lockID` int(11) DEFAULT NULL, + `lockDate` datetime DEFAULT NULL, + `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`ID`), + KEY `tableName` (`tableName`), + KEY `lockID` (`lockID`) +); \ No newline at end of file From 74e425491c3c5577bf9aa18404d54cc87549dab9 Mon Sep 17 00:00:00 2001 From: Jonathan Samples Date: Tue, 8 Sep 2015 08:22:57 -0700 Subject: [PATCH 10/20] Added redis set for class->objID --- .../percero/agents/sync/access/RedisAccessManager.java | 9 ++++++++- .../com/percero/agents/sync/access/RedisKeyUtils.java | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index cdcc43b..75ee296 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -830,7 +830,11 @@ private Long upsertRedisAccessJournal(String userId, String clientId, String cla // Need to add the ObjectID to the Client's AccessJournals set. String clientAccessJournalKey = RedisKeyUtils.clientAccessJournal(clientId); redisDataStore.addSetValue(clientAccessJournalKey, RedisKeyUtils.objectId(className, classId)); - + + // Add to the class's AccessJournals set + String classAccessJournalKey = RedisKeyUtils.classAccessJournal(className); + redisDataStore.addSetValue(classAccessJournalKey, classId); + // Need to add the ClientID to the Object's AccessJournal set. return redisDataStore.addSetValue(key, clientId); } catch(Exception e) { @@ -984,6 +988,9 @@ public void removeAccessJournalsByObject(ClassIDPair classIdPair) { // } // } + String classAccessJournalKey = RedisKeyUtils.classAccessJournal(classIdPair.getClassName()); + redisDataStore.removeSetValue(classAccessJournalKey, classIdPair.getID()); + // Now delete the AccessJournal record. redisDataStore.deleteKey(accessJournalKey); } diff --git a/src/main/java/com/percero/agents/sync/access/RedisKeyUtils.java b/src/main/java/com/percero/agents/sync/access/RedisKeyUtils.java index 4cd1cb4..8dd3df0 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisKeyUtils.java +++ b/src/main/java/com/percero/agents/sync/access/RedisKeyUtils.java @@ -111,6 +111,10 @@ public static String accessJournalPrefix() { public static String clientAccessJournal(String clientId) { return (new StringBuilder(INT_64).append("c:").append(ACCESS_JOURNAL_PREFIX).append(clientId)).toString(); } + + public static String classAccessJournal(String className) { + return (new StringBuilder(INT_64).append("class:").append(ACCESS_JOURNAL_PREFIX).append(className)).toString(); + } public static String historicalObject(String className, String classId) { return (new StringBuilder(INT_128).append("ho:").append(className).append(":").append(classId)).toString(); From d53729ceee997e2b78783c62c37261eeaedb4237 Mon Sep 17 00:00:00 2001 From: Jonathan Samples Date: Tue, 8 Sep 2015 08:24:18 -0700 Subject: [PATCH 11/20] Removed bad comment --- .../java/com/percero/agents/sync/access/RedisAccessManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index 75ee296..5149ffa 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -566,7 +566,6 @@ public void destroyClient(String clientId) { * This function checks to see if a User has no more UserDevices. If they do not have * any, then it removes all the User's entries in ALL AccessJournal sets. * - * @param userId * @param clientId */ @SuppressWarnings("unchecked") From 4d1c298758c8a3146769699d1e647557a57cfbb7 Mon Sep 17 00:00:00 2001 From: Jonathan Samples Date: Wed, 9 Sep 2015 08:13:28 -0700 Subject: [PATCH 12/20] Finished routines to maintain class access journals --- .../sync/access/RedisAccessManager.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index 5149ffa..65b6d26 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -566,7 +566,7 @@ public void destroyClient(String clientId) { * This function checks to see if a User has no more UserDevices. If they do not have * any, then it removes all the User's entries in ALL AccessJournal sets. * - * @param clientId + * @param clientId */ @SuppressWarnings("unchecked") @Transactional @@ -577,6 +577,18 @@ private void deleteClientAccessJournals(String clientId) { // Now remove the Client's AccessJournal key. redisDataStore.deleteKey(clientAccessJournalsKey); + + // Check to see if each Object's access journal set is empty and if so remove it + // from the class access journal set + for(String caj : clientAccessJournals){ + if(redisDataStore.getSetIsEmpty(RedisKeyUtils.ACCESS_JOURNAL_PREFIX+caj)){ + String[] parts = caj.split(":"); + String className = parts[0]; + String ID = parts[1]; + String classAccessJournalKey = RedisKeyUtils.classAccessJournal(className); + redisDataStore.removeSetValue(classAccessJournalKey, ID); + } + } } @SuppressWarnings("unchecked") @@ -831,8 +843,11 @@ private Long upsertRedisAccessJournal(String userId, String clientId, String cla redisDataStore.addSetValue(clientAccessJournalKey, RedisKeyUtils.objectId(className, classId)); // Add to the class's AccessJournals set - String classAccessJournalKey = RedisKeyUtils.classAccessJournal(className); - redisDataStore.addSetValue(classAccessJournalKey, classId); + if(classId != null && !classId.isEmpty() && !classId.equals("0")) { + log.info("Adding to class AccessJournals: "+classId); + String classAccessJournalKey = RedisKeyUtils.classAccessJournal(className); + redisDataStore.addSetValue(classAccessJournalKey, classId); + } // Need to add the ClientID to the Object's AccessJournal set. return redisDataStore.addSetValue(key, clientId); From 8b603e417817d37e4e1a821a9f3434965b98b4e7 Mon Sep 17 00:00:00 2001 From: Jonathan Samples Date: Thu, 10 Sep 2015 08:17:00 -0700 Subject: [PATCH 13/20] Implemented whole table update --- .../agents/sync/access/AccessManager.java | 10 +++ .../agents/sync/access/IAccessManager.java | 2 + .../sync/access/RedisAccessManager.java | 8 +++ .../agents/sync/datastore/RedisDataStore.java | 5 ++ .../sync/jobs/UpdateTableProcessor.java | 66 +++++++++++++++---- .../jobs/UpdateTableProcessorFactory.java | 6 +- 6 files changed, 85 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/percero/agents/sync/access/AccessManager.java b/src/main/java/com/percero/agents/sync/access/AccessManager.java index 33b1fae..6bfcfac 100644 --- a/src/main/java/com/percero/agents/sync/access/AccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/AccessManager.java @@ -870,6 +870,16 @@ public List getObjectAccessJournals(String className, String classId) th return result; } + @Override + public Set getClassAccessJournalIDs(String className) { + return null; + } + + @Override + public long getNumClientsInterestedInWholeClass(String className) { + return 0; + } + @SuppressWarnings("unchecked") public Map> getClientAccessess(Collection classIdPairs) throws Exception { Map> result = new HashMap>(); diff --git a/src/main/java/com/percero/agents/sync/access/IAccessManager.java b/src/main/java/com/percero/agents/sync/access/IAccessManager.java index 7875993..6509912 100644 --- a/src/main/java/com/percero/agents/sync/access/IAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/IAccessManager.java @@ -153,6 +153,8 @@ public Set findClientByUserIdDeviceId(String deviceId, String userId) * @throws Exception */ public List getObjectAccessJournals(String className, String classId) throws Exception; + Set getClassAccessJournalIDs(String className); + long getNumClientsInterestedInWholeClass(String className); public void removeAccessJournalsByObject(ClassIDPair classIdPair); diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index 65b6d26..dbea315 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -899,6 +899,14 @@ public List getObjectAccessJournals(String className, String classId) th return result; } + public Set getClassAccessJournalIDs(String className){ + return (Set) redisDataStore.getSetValue(RedisKeyUtils.classAccessJournal(className)); + } + + public long getNumClientsInterestedInWholeClass(String className){ + return redisDataStore.getSetSize(RedisKeyUtils.accessJournal(className,"0")); + } + public List checkUserListAccessRights(Collection clientIdList, String className, String classId) throws Exception { List result = new ArrayList(); diff --git a/src/main/java/com/percero/agents/sync/datastore/RedisDataStore.java b/src/main/java/com/percero/agents/sync/datastore/RedisDataStore.java index cfbcb4d..fbe8c68 100644 --- a/src/main/java/com/percero/agents/sync/datastore/RedisDataStore.java +++ b/src/main/java/com/percero/agents/sync/datastore/RedisDataStore.java @@ -183,6 +183,11 @@ public Map getHashEntries( final String key ) { public Long getHashSize( final String key ) { return template.opsForHash().size(key); } + + @Transactional + public Long getSetSize( final String key ) { + return template.opsForSet().size(key); + } @Transactional public void deleteHashKey( final String key, final Object hashKey ) { diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java index 0bfd839..0c81dfc 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java @@ -1,5 +1,6 @@ package com.percero.agents.sync.jobs; +import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.cache.CacheManager; import com.percero.agents.sync.helpers.PostDeleteHelper; import com.percero.agents.sync.helpers.PostPutHelper; @@ -19,8 +20,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.util.Date; -import java.util.Random; +import java.util.*; /** * Responsible for querying an update table and processing the rows. @@ -38,6 +38,7 @@ public class UpdateTableProcessor { private IManifest manifest; private CacheManager cacheManager; private DataProviderManager dataProviderManager; + private IAccessManager accessManager; public UpdateTableProcessor(String tableName, UpdateTableConnectionFactory connectionFactory, @@ -45,7 +46,8 @@ public UpdateTableProcessor(String tableName, PostDeleteHelper postDeleteHelper, PostPutHelper postPutHelper, CacheManager cacheManager, - DataProviderManager dataProviderManager) + DataProviderManager dataProviderManager, + IAccessManager accessManager) { this.tableName = tableName; this.connectionFactory = connectionFactory; @@ -54,6 +56,7 @@ public UpdateTableProcessor(String tableName, this.manifest = manifest; this.cacheManager = cacheManager; this.dataProviderManager= dataProviderManager; + this.accessManager = accessManager; } /** @@ -84,6 +87,7 @@ public ProcessorResult process(){ result.addResult(row.getType().toString(), false, ""); } }catch(Exception e){ + logger.warn("Failed to process update: "+ e.getMessage(), e); result.addResult(row.getType().toString(), false, e.getMessage()); } @@ -147,17 +151,32 @@ private boolean processDeleteSingle(UpdateTableRow row) throws Exception{ */ private boolean processUpdateSingle(UpdateTableRow row) throws Exception{ Class clazz = getClassForTableName(row.getTableName()); + List list = new ArrayList(); + list.add(row.getRowId()); + processUpdates(clazz.getCanonicalName(), list); + return true; + } + + /** + * Takes a class and list of ids that need to be pushed out + * @param className + * @param Ids + * @throws Exception + */ + private void processUpdates(String className, Collection Ids) throws Exception{ IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(clazz.getName()); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - ClassIDPair pair = new ClassIDPair(row.getRowId(), clazz.getCanonicalName()); - IPerceroObject object = dataProvider.systemGetById(pair, true); - if(object != null){ - cacheManager.updateCachedObject(object, null); - postPutHelper.postPutObject(pair, null, null, true, null); + for(String ID : Ids) { + ClassIDPair pair = new ClassIDPair(ID, className); + IPerceroObject object = dataProvider.systemGetById(pair, true); + + if (object != null) { + cacheManager.updateCachedObject(object, null); + postPutHelper.postPutObject(pair, null, null, true, null); + } } - return true; } /** @@ -185,10 +204,35 @@ private boolean processDeleteTable(UpdateTableRow row){ * @param row * @return */ - private boolean processUpdateTable(UpdateTableRow row){ + private boolean processUpdateTable(UpdateTableRow row) throws Exception{ + Class clazz = getClassForTableName(row.getTableName()); + + Set accessedIds = null; + // If there are any clients that have asked for all objects in a class then we have to push everything + if(accessManager.getNumClientsInterestedInWholeClass(clazz.getName()) > 0) + accessedIds = getAllIdsForTable(row.getTableName()); + else + accessedIds = accessManager.getClassAccessJournalIDs(clazz.getName()); + + processUpdates(clazz.getCanonicalName(), accessedIds); return true; } + private Set getAllIdsForTable(String tableName) throws SQLException{ + Set result = new HashSet(); + String query = "select ID from "+tableName; + try(Connection connection = connectionFactory.getConnection(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery(query)){ + + while(resultSet.next()){ + result.add(resultSet.getString("ID")); + } + } + + return result; + } + /** * Process a whole table with inserts * @param row diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java index 0c8e392..cbf6b89 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java @@ -1,5 +1,6 @@ package com.percero.agents.sync.jobs; +import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.cache.CacheManager; import com.percero.agents.sync.helpers.PostDeleteHelper; import com.percero.agents.sync.helpers.PostPutHelper; @@ -33,8 +34,11 @@ public class UpdateTableProcessorFactory { @Autowired DataProviderManager dataProviderManager; + @Autowired + IAccessManager accessManager; + public UpdateTableProcessor getProcessor(String tableName){ return new UpdateTableProcessor(tableName, connectionFactory, manifest, - postDeleteHelper, postPutHelper, cacheManager, dataProviderManager); + postDeleteHelper, postPutHelper, cacheManager, dataProviderManager, accessManager); } } From dc246d2af8a61282bbd3ddf11e8c5bde6e577273 Mon Sep 17 00:00:00 2001 From: Jonathan Samples Date: Sat, 12 Sep 2015 07:46:37 -0700 Subject: [PATCH 14/20] Full table update --- .../sync/jobs/UpdateTableProcessor.java | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java index 0c81dfc..24b9dfc 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java @@ -4,11 +4,10 @@ import com.percero.agents.sync.cache.CacheManager; import com.percero.agents.sync.helpers.PostDeleteHelper; import com.percero.agents.sync.helpers.PostPutHelper; -import com.percero.agents.sync.metadata.IMappedClassManager; -import com.percero.agents.sync.metadata.MappedClass; -import com.percero.agents.sync.metadata.MappedClassManagerFactory; +import com.percero.agents.sync.metadata.*; import com.percero.agents.sync.services.DataProviderManager; import com.percero.agents.sync.services.IDataProvider; +import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.ClassIDPair; import com.percero.framework.bl.IManifest; import com.percero.framework.vo.IPerceroObject; @@ -195,7 +194,17 @@ private boolean processInsertSingle(UpdateTableRow row) throws Exception{ * @param row * @return */ - private boolean processDeleteTable(UpdateTableRow row){ + private boolean processDeleteTable(UpdateTableRow row) throws Exception{ + Class clazz = getClassForTableName(row.getTableName()); + Set accessedIds = accessManager.getClassAccessJournalIDs(clazz.getName()); + Set allIds = getAllIdsForTable(row.getTableName()); + + // Now we have the set that has been removed that we care about + accessedIds.removeAll(allIds); + for(String id : accessedIds){ + postDeleteHelper.postDeleteObject(new ClassIDPair(id, clazz.getCanonicalName()), null, null, true); + } + return true; } @@ -239,6 +248,32 @@ private Set getAllIdsForTable(String tableName) throws SQLException{ * @return */ private boolean processInsertTable(UpdateTableRow row){ + Class clazz = getClassForTableName(row.getTableName()); + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(clazz.getName()); + +// TODO: uncomment and implement +// for(MappedFieldPerceroObject nextMappedField : mappedClass.externalizablePerceroObjectFields) { +// try { +// if (nextMappedField.getReverseMappedField() != null) { +// IPerceroObject fieldValue = (IPerceroObject) nextMappedField.getValue(perceroObject); +// if (fieldValue != null) { +// ClassIDPair fieldPair = BaseDataObject.toClassIdPair(fieldValue); +// +// Collection classChangedFields = changedObjects.get(fieldPair); +// if (classChangedFields == null) { +// classChangedFields = new HashSet(); +// changedObjects.put(fieldPair, classChangedFields); +// } +// MappedField reverseMappedField = nextMappedField.getReverseMappedField(); +// classChangedFields.add(reverseMappedField); +// } +// } +// } catch(Exception e) { +// log.error("Error in postCreateObject " + mappedClass.className + "." + nextMappedField.getField().getName(), e); +// } +// } + return true; } From f51f3206168dfca11533e0945c560832dcb49b76 Mon Sep 17 00:00:00 2001 From: Jonathan Samples Date: Wed, 16 Sep 2015 07:46:46 -0700 Subject: [PATCH 15/20] Started adding the java test client --- .../sync/jobs/UpdateTableProcessor.java | 82 ++++++++----- .../sync/metadata/IMappedClassManager.java | 7 +- .../sync/metadata/MappedClassManager.java | 6 + .../sync/jobs/UpdateTableProcessorTest.java | 55 ++++++--- .../java/com/percero/client/AStackClient.java | 74 ++++++++++++ .../percero/client/AStackClientFactory.java | 18 +++ .../com/percero/client/AStackClientTest.java | 41 +++++++ .../com/percero/client/AStackRPCService.java | 23 ++++ .../java/com/percero/client/Callback.java | 9 ++ src/test/java/com/percero/example/Circle.java | 114 ++++++++++++++++++ src/test/java/com/percero/example/Email.java | 6 +- src/test/java/com/percero/example/Person.java | 53 ++++++++ .../java/com/percero/test/utils/AuthUtil.java | 24 ++++ .../com/percero/test/utils/CleanerUtil.java | 58 +++++++++ .../resources/properties/test/env.properties | 2 +- .../spring/update_table_processor.xml | 6 + src/test/resources/update_table_test_sql.md | 109 +++++++++++++++++ 17 files changed, 634 insertions(+), 53 deletions(-) create mode 100644 src/test/java/com/percero/client/AStackClient.java create mode 100644 src/test/java/com/percero/client/AStackClientFactory.java create mode 100644 src/test/java/com/percero/client/AStackClientTest.java create mode 100644 src/test/java/com/percero/client/AStackRPCService.java create mode 100644 src/test/java/com/percero/client/Callback.java create mode 100644 src/test/java/com/percero/example/Circle.java create mode 100644 src/test/java/com/percero/test/utils/AuthUtil.java create mode 100644 src/test/java/com/percero/test/utils/CleanerUtil.java create mode 100644 src/test/resources/update_table_test_sql.md diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java index 24b9dfc..a30c9e5 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java @@ -7,7 +7,6 @@ import com.percero.agents.sync.metadata.*; import com.percero.agents.sync.services.DataProviderManager; import com.percero.agents.sync.services.IDataProvider; -import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.ClassIDPair; import com.percero.framework.bl.IManifest; import com.percero.framework.vo.IPerceroObject; @@ -140,6 +139,7 @@ private boolean processRow(UpdateTableRow row) throws Exception{ private boolean processDeleteSingle(UpdateTableRow row) throws Exception{ Class clazz = getClassForTableName(row.getTableName()); postDeleteHelper.postDeleteObject(new ClassIDPair(row.getRowId(), clazz.getCanonicalName()), null, null, true); + updateReferences(clazz.getName()); return true; } @@ -152,7 +152,8 @@ private boolean processUpdateSingle(UpdateTableRow row) throws Exception{ Class clazz = getClassForTableName(row.getTableName()); List list = new ArrayList(); list.add(row.getRowId()); - processUpdates(clazz.getCanonicalName(), list); + processUpdates(clazz.getName(), list); + updateReferences(clazz.getName()); return true; } @@ -186,6 +187,7 @@ private void processUpdates(String className, Collection Ids) throws Exc private boolean processInsertSingle(UpdateTableRow row) throws Exception{ Class clazz = getClassForTableName(row.getTableName()); postPutHelper.postPutObject(new ClassIDPair(row.getRowId(), clazz.getCanonicalName()), null, null, true, null); + updateReferences(clazz.getName()); return true; } @@ -205,6 +207,8 @@ private boolean processDeleteTable(UpdateTableRow row) throws Exception{ postDeleteHelper.postDeleteObject(new ClassIDPair(id, clazz.getCanonicalName()), null, null, true); } + updateReferences(clazz.getName()); + return true; } @@ -223,7 +227,9 @@ private boolean processUpdateTable(UpdateTableRow row) throws Exception{ else accessedIds = accessManager.getClassAccessJournalIDs(clazz.getName()); - processUpdates(clazz.getCanonicalName(), accessedIds); + processUpdates(clazz.getName(), accessedIds); + updateReferences(clazz.getName()); + return true; } @@ -247,36 +253,56 @@ private Set getAllIdsForTable(String tableName) throws SQLException{ * @param row * @return */ - private boolean processInsertTable(UpdateTableRow row){ - Class clazz = getClassForTableName(row.getTableName()); - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(clazz.getName()); + private boolean processInsertTable(UpdateTableRow row) throws Exception { + + MappedClass mappedClass = getMappedClassForTableName(row.getTableName()); -// TODO: uncomment and implement -// for(MappedFieldPerceroObject nextMappedField : mappedClass.externalizablePerceroObjectFields) { -// try { -// if (nextMappedField.getReverseMappedField() != null) { -// IPerceroObject fieldValue = (IPerceroObject) nextMappedField.getValue(perceroObject); -// if (fieldValue != null) { -// ClassIDPair fieldPair = BaseDataObject.toClassIdPair(fieldValue); -// -// Collection classChangedFields = changedObjects.get(fieldPair); -// if (classChangedFields == null) { -// classChangedFields = new HashSet(); -// changedObjects.put(fieldPair, classChangedFields); -// } -// MappedField reverseMappedField = nextMappedField.getReverseMappedField(); -// classChangedFields.add(reverseMappedField); -// } -// } -// } catch(Exception e) { -// log.error("Error in postCreateObject " + mappedClass.className + "." + nextMappedField.getField().getName(), e); -// } -// } + // if any client needs all of this class then the only choice we have is to push everything + if(accessManager.getNumClientsInterestedInWholeClass(mappedClass.className) > 0){ + Set allIds = getAllIdsForTable(row.getTableName()); + for(String id : allIds) + postPutHelper.postPutObject(new ClassIDPair(id, mappedClass.className), null, null, true, null); + } + + updateReferences(mappedClass.className); return true; } + private MappedClass getMappedClassForTableName(String tableName){ + Class clazz = getClassForTableName(tableName); + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(clazz.getName()); + return mappedClass; + } + + /** + * Finds all back references to this class and pushes updates to all of them. + * @param className + */ + private void updateReferences(String className){ + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); + // Go through each mapped field and push all objects of that associated type (just in case any has a reference to a new row + // in the updated table) + // -- + // TODO: is this right? Is it enough to only check the relationships on this class or do we need to look + // through all of the mapped classes? + for(MappedFieldPerceroObject nextMappedField : mappedClass.externalizablePerceroObjectFields) { + try { + // Only care about it if it has a reverse relationship + MappedField mappedField = nextMappedField.getReverseMappedField(); + if (mappedField != null) { + // Find all of this type and push down an update to all + Set ids = accessManager.getClassAccessJournalIDs(mappedField.getMappedClass().className); + processUpdates(mappedField.getMappedClass().className, ids); + } + } catch(Exception e) { + logger.error("Error in postCreateObject " + mappedClass.className + "." + nextMappedField.getField().getName(), e); + } + } + } + /** * Pulls a row off the update table and locks it so that other * processors don't duplicate the work diff --git a/src/main/java/com/percero/agents/sync/metadata/IMappedClassManager.java b/src/main/java/com/percero/agents/sync/metadata/IMappedClassManager.java index 55cfac1..f522792 100644 --- a/src/main/java/com/percero/agents/sync/metadata/IMappedClassManager.java +++ b/src/main/java/com/percero/agents/sync/metadata/IMappedClassManager.java @@ -1,7 +1,10 @@ package com.percero.agents.sync.metadata; +import java.util.Collection; + public interface IMappedClassManager { - public void addMappedClass(MappedClass theMappedClass); - public MappedClass getMappedClassByClassName(String aClassName); + void addMappedClass(MappedClass theMappedClass); + MappedClass getMappedClassByClassName(String aClassName); + Collection getAllMappedClasses(); } diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedClassManager.java b/src/main/java/com/percero/agents/sync/metadata/MappedClassManager.java index 9a46c6d..95598a0 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedClassManager.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedClassManager.java @@ -1,5 +1,6 @@ package com.percero.agents.sync.metadata; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Random; @@ -24,4 +25,9 @@ public MappedClass getMappedClassByClassName(String aClassName) { return mc; } + @Override + public Collection getAllMappedClasses() { + return mappedClassesByName.values(); + } + } diff --git a/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java b/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java index 7d9a0bf..c1d0757 100644 --- a/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java +++ b/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java @@ -2,6 +2,8 @@ import com.percero.example.Email; import com.percero.example.Person; +import com.percero.test.utils.AuthUtil; +import com.percero.test.utils.CleanerUtil; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -12,6 +14,7 @@ import java.sql.Connection; import java.sql.ResultSet; +import java.sql.SQLException; import java.sql.Statement; /** @@ -27,6 +30,10 @@ public class UpdateTableProcessorTest { UpdateTableConnectionFactory connectionFactory; @Autowired UpdateTablePoller poller; + @Autowired + CleanerUtil cleanerUtil; + @Autowired + AuthUtil authUtil; String tableName = "update_table"; @@ -34,29 +41,13 @@ public class UpdateTableProcessorTest { public void before() throws Exception{ // Disable the poller so it doesn't step on our toes poller.enabled = false; + cleanerUtil.cleanAll(); try(Connection connection = connectionFactory.getConnection(); Statement statement = connection.createStatement()) { + // Truncate the update table String sql = "delete from " + tableName; statement.executeUpdate(sql); - - // Add some fixture data - statement.executeUpdate("insert into " + tableName + "(tableName, rowId, type) values " + - "('Email','1','UPDATE')," + - "('Person','1','INSERT')," + - "('Block','1','DELETE')"); - } - } - - @Test - public void test() throws Exception{ - try(Connection connection = connectionFactory.getConnection(); - Statement statement = connection.createStatement();) - { - String sql = "select count(*) as 'count' from " + tableName; - ResultSet resultSet = statement.executeQuery(sql); - Assert.assertTrue(resultSet.next()); - Assert.assertEquals(3, resultSet.getInt("count")); } } @@ -81,8 +72,22 @@ public void getClassForTableName_NotFound() throws Exception{ Assert.assertNull(clazz); } + // Shared setup method + public void setupThreeRowsInUpdateTable() throws SQLException{ + try(Connection connection = connectionFactory.getConnection(); + Statement statement = connection.createStatement()) + { + // Add some fixture data + statement.executeUpdate("insert into " + tableName + "(tableName, rowId, type) values " + + "('Email','1','UPDATE')," + + "('Person','1','INSERT')," + + "('Block','1','DELETE')"); + } + } + @Test public void getRow() throws Exception { + setupThreeRowsInUpdateTable(); UpdateTableProcessor processor = processorFactory.getProcessor(tableName); UpdateTableRow row = processor.getRow(); @@ -104,7 +109,9 @@ public void getRow() throws Exception { @Test - public void process() throws Exception { + public void processMultipleRows() throws Exception { + setupThreeRowsInUpdateTable(); + UpdateTableProcessor processor = processorFactory.getProcessor(tableName); ProcessorResult result = processor.process(); Assert.assertEquals(3, result.getTotal()); @@ -120,4 +127,14 @@ public void process() throws Exception { } } + @Test + public void singleRowInsertAllList(){ + + } + + @Test + public void singleRowInsertRefList(){ + + } + } diff --git a/src/test/java/com/percero/client/AStackClient.java b/src/test/java/com/percero/client/AStackClient.java new file mode 100644 index 0000000..f9c39e1 --- /dev/null +++ b/src/test/java/com/percero/client/AStackClient.java @@ -0,0 +1,74 @@ +package com.percero.client; + +import com.percero.agents.auth.vo.AuthenticationRequest; +import com.percero.agents.auth.vo.AuthenticationResponse; +import com.percero.agents.auth.vo.UserToken; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageListener; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; + +import java.util.UUID; + +/** + * Intended to maintain session with the server and listen for + * push messages. + */ +public class AStackClient { + + /** + * Some service deps + */ + private AStackRPCService rpcService; + private String clientId = UUID.randomUUID().toString(); + private ConnectionFactory amqpConnectionFactory; + public AStackClient(AStackRPCService rpcService, ConnectionFactory amqpConnectionFactory){ + this.rpcService = rpcService; + this.amqpConnectionFactory = amqpConnectionFactory; + } + + /** + * Some internal state + */ + private UserToken userToken; + + public boolean authenticateAnonymously(){ + AuthenticationRequest request = new AuthenticationRequest(); + request.setAuthProvider("anonymous"); + request.setClientId(clientId); + + AuthenticationResponse response = rpcService.authenticate(request); + userToken = response.getResult(); + boolean result = (userToken != null); + if(result){ + setupClientQueueAndStartListening(); + } + + return result; + } + + /** + * Sets up the queue to listen for messages to the client (including responses to RPC) + */ + private SimpleMessageListenerContainer listenerContainer; + private void setupClientQueueAndStartListening(){ + listenerContainer = new SimpleMessageListenerContainer(amqpConnectionFactory); + listenerContainer.setQueueNames(clientId); + listenerContainer.setMessageListener(getMessageListener()); + listenerContainer.start(); + } + + private MessageListener messageListener; + private MessageListener getMessageListener(){ + if(messageListener == null) + messageListener = new MessageListener() { + @Override + public void onMessage(Message message) { + String key = message.getMessageProperties().getReceivedRoutingKey(); + System.out.println("Got Message from server: "+key); + } + }; + + return messageListener; + } +} diff --git a/src/test/java/com/percero/client/AStackClientFactory.java b/src/test/java/com/percero/client/AStackClientFactory.java new file mode 100644 index 0000000..2982c9f --- /dev/null +++ b/src/test/java/com/percero/client/AStackClientFactory.java @@ -0,0 +1,18 @@ +package com.percero.client; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Created by jonnysamps on 9/14/15. + */ +@Component +public class AStackClientFactory { + + @Autowired + AStackRPCService rpcService; + + public AStackClient getClient(){ + return new AStackClient(rpcService); + } +} diff --git a/src/test/java/com/percero/client/AStackClientTest.java b/src/test/java/com/percero/client/AStackClientTest.java new file mode 100644 index 0000000..517a89c --- /dev/null +++ b/src/test/java/com/percero/client/AStackClientTest.java @@ -0,0 +1,41 @@ +package com.percero.client; + +import com.percero.agents.sync.jobs.UpdateTablePoller; +import com.percero.test.utils.CleanerUtil; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import static org.junit.Assert.*; + +/** + * Created by jonnysamps on 9/14/15. + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:spring/update_table_processor.xml" }) +public class AStackClientTest { + + @Autowired + AStackClientFactory clientFactory; + + @Autowired + CleanerUtil cleanerUtil; + + @Autowired + UpdateTablePoller poller; + + @Before + public void before(){ + poller.enabled = false; + cleanerUtil.cleanAll(); + } + + @Test + public void authenticateAnonymously(){ + AStackClient client = clientFactory.getClient(); + boolean result = client.authenticateAnonymously(); + assertTrue(result); + } +} diff --git a/src/test/java/com/percero/client/AStackRPCService.java b/src/test/java/com/percero/client/AStackRPCService.java new file mode 100644 index 0000000..0818695 --- /dev/null +++ b/src/test/java/com/percero/client/AStackRPCService.java @@ -0,0 +1,23 @@ +package com.percero.client; + +import com.percero.agents.auth.vo.AuthenticationRequest; +import com.percero.agents.auth.vo.AuthenticationResponse; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Main interface for communicating to the backend through AMQP + * Created by jonnysamps on 9/13/15. + */ +@Component +public class AStackRPCService { + + @Autowired + AmqpTemplate amqpTemplate; + + public AuthenticationResponse authenticate(AuthenticationRequest request){ + return (AuthenticationResponse) amqpTemplate.convertSendAndReceive("authenticate", request); + } + +} diff --git a/src/test/java/com/percero/client/Callback.java b/src/test/java/com/percero/client/Callback.java new file mode 100644 index 0000000..ae6ac4e --- /dev/null +++ b/src/test/java/com/percero/client/Callback.java @@ -0,0 +1,9 @@ +package com.percero.client; + +/** + * Interface to define the way that the client does async processing with callbacks + * Created by jonnysamps on 9/15/15. + */ +public interface Callback { + void execute(T result); +} diff --git a/src/test/java/com/percero/example/Circle.java b/src/test/java/com/percero/example/Circle.java new file mode 100644 index 0000000..d398177 --- /dev/null +++ b/src/test/java/com/percero/example/Circle.java @@ -0,0 +1,114 @@ +package com.percero.example; + +import com.google.gson.JsonObject; +import com.percero.agents.sync.metadata.annotations.Externalize; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.serial.JsonUtils; +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; + +import javax.persistence.*; +import java.io.IOException; +import java.io.Serializable; + +@Entity +public class Circle extends BaseDataObject implements Serializable{ + + ////////////////////////////////////////////////////// + // Properties + ////////////////////////////////////////////////////// + @Id + @Externalize + @Column(unique=true,name="ID") + private String ID; + @JsonProperty(value="ID") + public String getID() { + return this.ID; + } + @JsonProperty(value="ID") + public void setID(String value) { + this.ID = value; + } + + @Column + @Externalize + private String color; + public String getColor() { + return this.color; + } + public void setColor(String value) + { + this.color = value; + } + + ////////////////////////////////////////////////////// + // Source Relationships + ////////////////////////////////////////////////////// + @Externalize + @JoinColumn(name="person_ID") + @org.hibernate.annotations.ForeignKey(name="FK_Person_person_TO_Circle") + @ManyToOne(fetch=FetchType.LAZY, optional=false) + private Person person; + public Person getPerson() { + return this.person; + } + public void setPerson(Person value) { + this.person = value; + } + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + String objectJson = super.retrieveJson(objectMapper); + + // Properties + objectJson += ",\"color\":"; + if (getColor() == null) + objectJson += "null"; + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson += objectMapper.writeValueAsString(getColor()); + } catch (JsonGenerationException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson += "null"; + e.printStackTrace(); + } catch (IOException e) { + objectJson += "null"; + e.printStackTrace(); + } + } + + objectJson += ",\"person\":"; + if (getPerson() == null) + objectJson += "null"; + else { + try { + objectJson += getPerson().toEmbeddedJson(); + } catch(Exception e) { + objectJson += "null"; + } + } + objectJson += ""; + + return objectJson; + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + setColor(JsonUtils.getJsonString(jsonObject, "color")); + + // Source Relationships + this.person = JsonUtils.getJsonPerceroObject(jsonObject, "person"); + } +} diff --git a/src/test/java/com/percero/example/Email.java b/src/test/java/com/percero/example/Email.java index 84ca055..9264dac 100644 --- a/src/test/java/com/percero/example/Email.java +++ b/src/test/java/com/percero/example/Email.java @@ -97,13 +97,13 @@ public void setValue(String value) @JsonSerialize(using=BDOSerializer.class) @JsonDeserialize(using=BDODeserializer.class) @JoinColumn(name="user_ID") - @org.hibernate.annotations.ForeignKey(name="FK_User_user_TO_Email") + @org.hibernate.annotations.ForeignKey(name="FK_Person_person_TO_Email") @ManyToOne(fetch=FetchType.LAZY, optional=false) private Person person; public Person getPerson() { return this.person; } - public void setUser(Person value) { + public void setPerson(Person value) { this.person = value; } @@ -161,7 +161,7 @@ public String retrieveJson(ObjectMapper objectMapper) { objectJson += "null"; else { try { - objectJson += ((BaseDataObject) getPerson()).toEmbeddedJson(); + objectJson += getPerson().toEmbeddedJson(); } catch(Exception e) { objectJson += "null"; } diff --git a/src/test/java/com/percero/example/Person.java b/src/test/java/com/percero/example/Person.java index fb1b7b0..1dccf05 100644 --- a/src/test/java/com/percero/example/Person.java +++ b/src/test/java/com/percero/example/Person.java @@ -115,6 +115,25 @@ public void setPersonRoles(List value) { this.personRoles = value; } + @Externalize + @OneToMany(fetch=FetchType.LAZY, targetEntity=Email.class, mappedBy="person", cascade=javax.persistence.CascadeType.REMOVE) + private List emails; + public List getEmails() { + return this.emails; + } + public void setEmails(List value) { + this.emails = value; + } + + @Externalize + @OneToMany(fetch=FetchType.LAZY, targetEntity=Circle.class, mappedBy="person", cascade=javax.persistence.CascadeType.REMOVE) + private List circles; + public List getCircles() { + return this.circles; + } + public void setCircles(List value) { + this.circles = value; + } ////////////////////////////////////////////////////// // JSON @@ -212,10 +231,42 @@ public String retrieveJson(ObjectMapper objectMapper) { } } } + objectJson += "]"; + objectJson += ",\"emails\":["; + if (getEmails() != null) { + int emailsCounter = 0; + for(Email email : getEmails()) { + if (emailsCounter > 0) + objectJson += ","; + try { + objectJson += email.toEmbeddedJson(); + emailsCounter++; + } catch(Exception e) { + // Do nothing. + } + } + } + objectJson += "]"; + + objectJson += ",\"circles\":["; + if (getCircles() != null) { + int circlesCounter = 0; + for(Circle circle : getCircles()) { + if (circlesCounter > 0) + objectJson += ","; + try { + objectJson += circle.toEmbeddedJson(); + circlesCounter++; + } catch(Exception e) { + // Do nothing. + } + } + } objectJson += "]"; + return objectJson; } @@ -231,6 +282,8 @@ protected void fromJson(JsonObject jsonObject) { setLastName(com.percero.serial.JsonUtils.getJsonString(jsonObject, "lastName")); this.personRoles = (List) JsonUtils.getJsonListPerceroObject(jsonObject, "personRoles"); + this.emails = (List) JsonUtils.getJsonListPerceroObject(jsonObject, "emails"); + this.circles = (List) JsonUtils.getJsonListPerceroObject(jsonObject, "circles"); } } diff --git a/src/test/java/com/percero/test/utils/AuthUtil.java b/src/test/java/com/percero/test/utils/AuthUtil.java new file mode 100644 index 0000000..43d6ecb --- /dev/null +++ b/src/test/java/com/percero/test/utils/AuthUtil.java @@ -0,0 +1,24 @@ +package com.percero.test.utils; + +import com.percero.agents.auth.vo.AuthenticationRequest; +import com.percero.agents.auth.vo.AuthenticationResponse; +import com.percero.client.AStackRPCService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Created by jonnysamps on 9/13/15. + */ +@Component +public class AuthUtil { + + @Autowired + AStackRPCService rpcService; + + public AuthenticationResponse authenticateAnonymously(){ + AuthenticationRequest request = new AuthenticationRequest(); + request.setAuthProvider("anonymous"); + AuthenticationResponse response = (AuthenticationResponse) rpcService.authenticate(request); + return response; + } +} diff --git a/src/test/java/com/percero/test/utils/CleanerUtil.java b/src/test/java/com/percero/test/utils/CleanerUtil.java new file mode 100644 index 0000000..dd2f7a7 --- /dev/null +++ b/src/test/java/com/percero/test/utils/CleanerUtil.java @@ -0,0 +1,58 @@ +package com.percero.test.utils; + +import com.percero.agents.sync.metadata.IMappedClassManager; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClassManagerFactory; +import com.percero.agents.sync.services.PerceroRedisTemplate; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +/** + * Created by jonnysamps on 9/14/15. + */ +@Component +public class CleanerUtil { + + @Autowired + PerceroRedisTemplate redisTemplate; + + @Autowired + SessionFactory appSessionFactory; + + /** + * Wipe the database and redis + */ + public void cleanAll(){ + cleanDB(); + cleanCache(); + } + + @Transactional + public void cleanDB(){ + Session s = null; + try { + s = appSessionFactory.getCurrentSession(); + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + for (MappedClass mappedClass : mcm.getAllMappedClasses()) { + s.createQuery("delete from "+mappedClass.tableName).executeUpdate(); + } + } catch(Exception e){ + System.out.println(e.getMessage()); + } + } + + public void cleanCache(){ + RedisConnection connection = null; + try{ + connection = redisTemplate.getConnectionFactory().getConnection(); + connection.flushAll(); + } finally{ + if(connection != null) + connection.close(); + } + } +} diff --git a/src/test/resources/properties/test/env.properties b/src/test/resources/properties/test/env.properties index 2788f4e..fcc8219 100644 --- a/src/test/resources/properties/test/env.properties +++ b/src/test/resources/properties/test/env.properties @@ -65,7 +65,7 @@ pulseHttpAuth.hostPortAndContext=https://localhost:8900/auth pulseHttpAuth.trustAllCerts=true # Update Table -updateTable.tableNames=update_log +updateTable.tableNames=update_table updateTable.jdbcUrl=jdbc:mysql://localhost/as_example updateTable.username=root updateTable.password=root diff --git a/src/test/resources/spring/update_table_processor.xml b/src/test/resources/spring/update_table_processor.xml index f00f3b1..9d0ba64 100644 --- a/src/test/resources/spring/update_table_processor.xml +++ b/src/test/resources/spring/update_table_processor.xml @@ -43,6 +43,11 @@ + + + + + @@ -103,6 +108,7 @@ class="org.springframework.amqp.support.converter.JsonMessageConverter" /> + diff --git a/src/test/resources/update_table_test_sql.md b/src/test/resources/update_table_test_sql.md new file mode 100644 index 0000000..5c486a7 --- /dev/null +++ b/src/test/resources/update_table_test_sql.md @@ -0,0 +1,109 @@ +# Single Row Insert +## ALL list - PASSING +### First try +```sql +insert into Block set ID='1block', color='#aabbcc'; +insert into update_table set rowID='1block', tableName='Block', type='INSERT'; +``` + +### Second try +```sql +insert into Block set ID='2block', color='#8899aa'; +insert into update_table set rowID='2block', tableName='Block', type='INSERT'; +``` + +## Referenced list - PASSING +### First try +```sql +insert into Circle set ID='1circle', color='#11aa22', person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849'; +insert into update_table set rowID='1circle', tableName='Circle', type='INSERT'; +``` + +### Second try +```sql +insert into Circle set ID='2circle', color='#22bb33', person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849'; +insert into update_table set rowID='2circle', tableName='Circle', type='INSERT'; +``` + +# Whole Table Insert +## ALL list - PASSING +### First try +```sql +insert into Block set ID='3block', color='#a3b3c3'; +insert into Block set ID='4block', color='#a4b4c4'; +insert into update_table set rowID=null, tableName='Block', type='INSERT'; +``` + +### Second try +```sql +insert into Block set ID='5block', color='#b5b5c5'; +insert into Block set ID='6block', color='#b6b6c6'; +insert into update_table set rowID=null, tableName='Block', type='INSERT'; +``` + +## Reference list - PASSING + +```sql +-- First Try +insert into Circle set ID='3circle', color='#ccc333', person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849'; +insert into Circle set ID='4circle', color='#ccc444', person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849'; +insert into update_table set rowID=null, tableName='Circle', type='INSERT'; + +-- Second try +insert into Circle set ID='5circle', color='#ccc555', person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849'; +insert into Circle set ID='6circle', color='#ccc666', person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849'; +insert into update_table set rowID=null, tableName='Circle', type='INSERT'; +``` + +# Single Row Update +## Value update - PASSING +```sql +-- First Try -- +update Block set color='#333333' where ID='1' ; +insert into update_table set rowID='1', tableName='Block', type='UPDATE'; + +-- Second Try -- +update Block set color='#aaaaaa' where ID='1' ; +insert into update_table set rowID='1', tableName='Block', type='UPDATE'; +``` + +## Reference List - PASSING + +Make sure that when updating references that objects are added/removed the appropriate lists + +```sql +-- First Try -- +update Circle set color='green', person_ID='a11df72c-9aa5-4f75-ba41-ce4c4539fdbe' where ID='6circle'; +insert into update_table set rowID='6circle', tableName='Circle', type='UPDATE'; + +-- Second Try -- +update Circle set color='red', person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849' where ID='6circle'; +insert into update_table set rowID='6circle', tableName='Circle', type='UPDATE'; +``` + +# Whole Table update +## Value update - PASSING +```sql +-- First Try -- +update Block set color='coral'; +insert into update_table set rowID=null, tableName='Block', type='UPDATE'; + +-- Second Try -- +update Block set color='lightcoral'; +insert into update_table set rowID=null, tableName='Block', type='UPDATE'; +``` + +## Reference List - +```sql +-- First Try -- +update Circle set person_ID='' where person_ID='a11df72c-9aa5-4f75-ba41-ce4c4539fdbe'; +update Circle set person_ID='a11df72c-9aa5-4f75-ba41-ce4c4539fdbe' where person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849'; +update Circle set person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849' where person_ID=''; +insert into update_table set rowID=null, tableName='Circle', type='UPDATE'; + +-- Second try -- +update Circle set person_ID=null where person_ID='a11df72c-9aa5-4f75-ba41-ce4c4539fdbe'; +update Circle set person_ID='a11df72c-9aa5-4f75-ba41-ce4c4539fdbe' where person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849'; +update Circle set person_ID='e3d04ee4-e996-4f4a-9c5e-7e87e5685849' where person_ID=null; +insert into update_table set rowID=null, tableName='Circle', type='UPDATE'; +``` \ No newline at end of file From 77fbf0f51a6e924b1f7e18fb041c279bcdcf20a8 Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Wed, 16 Sep 2015 15:35:59 -0700 Subject: [PATCH 16/20] wip --- pom.xml | 5 +- .../auth/services/AuthProviderRegistry.java | 6 +- .../agents/sync/access/AccessManager.java | 2 +- .../sync/access/RedisAccessManager.java | 38 +- .../dao/ActiveStackHibernateSqlQuery.java | 174 +- .../dao/ActiveStackHibernateSqlSession.java | 62 +- .../sync/dao/ActiveStackMySQLDialect.java | 16 + .../dao/ActiveStackSqlSessionFactory.java | 76 +- .../percero/agents/sync/dao/DAORegistry.java | 39 + .../agents/sync/dao/IActiveStackSqlQuery.java | 46 +- .../sync/dao/IActiveStackSqlSession.java | 16 +- .../agents/sync/dao/IDataAccessObject.java | 16 +- .../sync/datastore/ICacheDataStore.java | 10 +- .../sync/datastore/JedisCacheDataStore.java | 648 ++++ .../sync/datastore/RedisCacheDataStore.java | 23 +- .../agents/sync/exceptions/SyncException.java | 4 + .../agents/sync/helpers/PostPutHelper.java | 4 +- .../sync/helpers/RedisPostClientHelper.java | 6 +- .../sync/hibernate/SyncHibernateUtils.java | 4 +- .../agents/sync/jobs/UpdateTablePoller.java | 100 +- .../agents/sync/metadata/JpqlQuery.java | 85 +- .../agents/sync/metadata/MappedClass.java | 2 +- .../agents/sync/metadata/MappedQuery.java | 115 +- .../agents/sync/metadata/SqlQuery.java | 102 +- .../agents/sync/services/AccessorService.java | 10 +- .../agents/sync/services/DAODataProvider.java | 1516 ++------ .../agents/sync/services/DAORegistry.java | 37 - .../sync/services/DataProviderManager.java | 9 + .../sync/services/HibernateDataProvider.java | 3354 ++++++++--------- .../agents/sync/services/IDataProvider.java | 34 +- .../sync/services/ISyncAgentService.java | 12 +- .../sync/services/RedisDataProvider.java | 362 -- .../sync/services/SyncAgentDataProvider.java | 167 +- .../sync/services/SyncAgentService.java | 64 +- .../percero/agents/sync/vo/ClassIDPairs.java | 7 + src/main/java/com/percero/util/DateUtils.java | 14 + .../spring/percero-spring-config.xml | 5 + 37 files changed, 3431 insertions(+), 3759 deletions(-) create mode 100644 src/main/java/com/percero/agents/sync/dao/ActiveStackMySQLDialect.java create mode 100644 src/main/java/com/percero/agents/sync/dao/DAORegistry.java create mode 100644 src/main/java/com/percero/agents/sync/datastore/JedisCacheDataStore.java delete mode 100644 src/main/java/com/percero/agents/sync/services/DAORegistry.java delete mode 100644 src/main/java/com/percero/agents/sync/services/RedisDataProvider.java create mode 100644 src/main/java/com/percero/util/DateUtils.java diff --git a/pom.xml b/pom.xml index 4f6d45e..14201af 100644 --- a/pom.xml +++ b/pom.xml @@ -251,7 +251,10 @@ com.google.apis google-api-services-oauth2 - v2-rev78-1.19.0 + v2-rev94-1.20.0 + com.google.http-client diff --git a/src/main/java/com/percero/agents/auth/services/AuthProviderRegistry.java b/src/main/java/com/percero/agents/auth/services/AuthProviderRegistry.java index b2e43a1..baaecb0 100644 --- a/src/main/java/com/percero/agents/auth/services/AuthProviderRegistry.java +++ b/src/main/java/com/percero/agents/auth/services/AuthProviderRegistry.java @@ -35,7 +35,7 @@ public void addProvider(IAuthProvider provider){ if(providerMap.containsKey(provider.getID())) logger.warn("Non-unique auth provider ID: "+provider.getID()); - providerMap.put(provider.getID(), provider); + providerMap.put(provider.getID().toLowerCase(), provider); } /** @@ -44,7 +44,7 @@ public void addProvider(IAuthProvider provider){ * @return */ public IAuthProvider getProvider(String ID){ - return providerMap.get(ID); + return providerMap.get(ID.toLowerCase()); } /** @@ -53,6 +53,6 @@ public IAuthProvider getProvider(String ID){ * @return */ public boolean hasProvider(String ID){ - return providerMap.containsKey(ID); + return providerMap.containsKey(ID.toLowerCase()); } } diff --git a/src/main/java/com/percero/agents/sync/access/AccessManager.java b/src/main/java/com/percero/agents/sync/access/AccessManager.java index 77440c0..1f43e48 100644 --- a/src/main/java/com/percero/agents/sync/access/AccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/AccessManager.java @@ -938,7 +938,7 @@ public List checkUserListAccessRights(List userIdList, String cl boolean hasAccess = true; // If the Read Query/Filter uses the ID, then we need to check against each ID here. if (isValidReadQuery) { - mappedClass.getReadQuery().setQueryParameters(query, classId, nextUserId); + mappedClass.getReadQuery().setQueryParameters(query.getQueryString(), classId, nextUserId); Number readFilterResult = (Number) query.uniqueResult(); if (readFilterResult == null || readFilterResult.intValue() <= 0) hasAccess = false; diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index 86bc1f0..6a850aa 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -356,10 +356,10 @@ else if (thePreviousClient.equals(clientId)) { // Update the UserDevice ClientID. String userDeviceHashKey = RedisKeyUtils.userDeviceHash(userId); - Collection userDeviceKeys = cacheDataStore.getHashKeys(userDeviceHashKey); - Iterator itrUserDevices = userDeviceKeys.iterator(); + Collection userDeviceKeys = cacheDataStore.getHashKeys(userDeviceHashKey); + Iterator itrUserDevices = userDeviceKeys.iterator(); while (itrUserDevices.hasNext()) { - String nextDeviceKey = (String) itrUserDevices.next(); + String nextDeviceKey = itrUserDevices.next(); if (thePreviousClient.equals(cacheDataStore.getHashValue(userDeviceHashKey, nextDeviceKey))) { cacheDataStore.addSetValue(RedisKeyUtils.deviceHash(nextDeviceKey), clientId); cacheDataStore.setHashValue(userDeviceHashKey, nextDeviceKey, clientId); @@ -514,12 +514,12 @@ public void destroyClient(String clientId) { // Delete Client's UserDevice. if (validUser) { String userDeviceHashKey = RedisKeyUtils.userDeviceHash(userId); - Collection userDeviceKeys = cacheDataStore.getHashKeys(userDeviceHashKey); + Collection userDeviceKeys = cacheDataStore.getHashKeys(userDeviceHashKey); int originalSize = userDeviceKeys.size(); int countRemoved = 0; - Iterator itrUserDevices = userDeviceKeys.iterator(); + Iterator itrUserDevices = userDeviceKeys.iterator(); while (itrUserDevices.hasNext()) { - String nextDeviceKey = (String) itrUserDevices.next(); + String nextDeviceKey = itrUserDevices.next(); if (clientId.equals(cacheDataStore.getHashValue(userDeviceHashKey, nextDeviceKey))) { // Since the client id being destroyed, the whole device history related to this client is also to be destroyed. // However, as a safety precaution, set the expiration for the device hash. @@ -688,10 +688,10 @@ public void postClients() { } // Now check Hibernating clients to see if any of those need to be removed - Map hibernatingClients = cacheDataStore.getHashEntries(RedisKeyUtils.clientsHibernated()); - Iterator> itrHibernatingClientsEntries = hibernatingClients.entrySet().iterator(); + Map hibernatingClients = cacheDataStore.getHashEntries(RedisKeyUtils.clientsHibernated()); + Iterator> itrHibernatingClientsEntries = hibernatingClients.entrySet().iterator(); while (itrHibernatingClientsEntries.hasNext()) { - Map.Entry nextEntry = itrHibernatingClientsEntries.next(); + Map.Entry nextEntry = itrHibernatingClientsEntries.next(); String nextHibernatingClientId = null; try { nextHibernatingClientId = (String) nextEntry.getKey(); @@ -1134,10 +1134,10 @@ public void removeChangeWatchers(String category, String subCategory) { String categoryKey = RedisKeyUtils.changeWatcherClass(category, subCategory); // Get all change watcher values associated with this object. - Set changeWatcherValueKeys = cacheDataStore.getHashKeys(categoryKey); - Iterator itrChangeWatcherValueKeys = changeWatcherValueKeys.iterator(); + Set changeWatcherValueKeys = cacheDataStore.getHashKeys(categoryKey); + Iterator itrChangeWatcherValueKeys = changeWatcherValueKeys.iterator(); while (itrChangeWatcherValueKeys.hasNext()) { - String nextChangeWatcherValueKey = (String) itrChangeWatcherValueKeys.next(); + String nextChangeWatcherValueKey = itrChangeWatcherValueKeys.next(); // If this is a RESULT key, then add it to the list to check. if (nextChangeWatcherValueKey.endsWith(":" + RedisKeyUtils.RESULT)) { int resultIndex = nextChangeWatcherValueKey.lastIndexOf(":" + RedisKeyUtils.RESULT); @@ -1167,10 +1167,10 @@ public void removeChangeWatchers(String category, String subCategory) { } String objectWatchedFieldKey = RedisKeyUtils.objectWatchedFields(category, subCategory); - Set objectWatcherValueKeys = cacheDataStore.getHashKeys(objectWatchedFieldKey); - Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); + Set objectWatcherValueKeys = cacheDataStore.getHashKeys(objectWatchedFieldKey); + Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); while (itrObjectWatcherValueKeys.hasNext()) { - String nextObjectWatcherValueKey = (String) itrObjectWatcherValueKeys.next(); + String nextObjectWatcherValueKey = itrObjectWatcherValueKeys.next(); // Get all fields for this object that are being watched and remove them. String changeWatcherKey = (String) cacheDataStore.getHashValue(objectWatchedFieldKey, nextObjectWatcherValueKey); @@ -1357,7 +1357,7 @@ protected Collection getChangeWatchersForField(ClassIDPair classIdPair, Collection changeWatchers = null; if (fieldWatcherKeys.size() > 0) { - changeWatchers = (Set) cacheDataStore.getSetUnion(null, fieldWatcherKeys); + changeWatchers = (Set) cacheDataStore.getSetUnion(noFieldWatcherKey, fieldWatcherKeys); } return changeWatchers; @@ -1374,10 +1374,10 @@ protected Set getAllFieldWatchersForObject(ClassIDPair classIdPair) { for(int i=0; i objectWatcherValueKeys = cacheDataStore.getHashKeys(nextKey); - Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); + Set objectWatcherValueKeys = cacheDataStore.getHashKeys(nextKey); + Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); while (itrObjectWatcherValueKeys.hasNext()) { - String nextObjectWatcherValueKey = (String) itrObjectWatcherValueKeys.next(); + String nextObjectWatcherValueKey = itrObjectWatcherValueKeys.next(); // Get all fields for this object that are being watched and remove them. String changeWatcherKey = (String) cacheDataStore.getHashValue(nextKey, nextObjectWatcherValueKey); diff --git a/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlQuery.java b/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlQuery.java index a2fc2eb..204c6f6 100644 --- a/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlQuery.java +++ b/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlQuery.java @@ -1,87 +1,87 @@ -package com.percero.agents.sync.dao; - -import java.util.Collection; -import java.util.Date; -import java.util.List; - -import org.hibernate.SQLQuery; - -public class ActiveStackHibernateSqlQuery implements IActiveStackSqlQuery { - - private SQLQuery query; - - public ActiveStackHibernateSqlQuery(SQLQuery query) { - this.query = query; - } - - public String getQueryString() { - return getQuery().getQueryString(); - } - - @Override - public String[] getNamedParameters() { - return getQuery().getNamedParameters(); - } - - public IActiveStackSqlQuery setString(int position, String val) { - getQuery().setString(position, val); - return this; - } - - public IActiveStackSqlQuery setString(String name, String val) { - getQuery().setString(name, val); - return this; - } - - public IActiveStackSqlQuery setDate(int position, Date val) { - getQuery().setDate(position, val); - return this; - } - - public IActiveStackSqlQuery setDate(String name, Date val) { - getQuery().setDate(name, val); - return this; - } - - public IActiveStackSqlQuery setParameter(int position, Object val) { - getQuery().setParameter(position, val); - return this; - } - - public IActiveStackSqlQuery setParameter(String name, Object val) { - getQuery().setParameter(name, val); - return this; - } - - public IActiveStackSqlQuery setParameterList(String name, Collection vals) { - getQuery().setParameterList(name, vals); - return this; - } - - public IActiveStackSqlQuery setParameterList(String name, Object[] vals) { - getQuery().setParameterList(name, vals); - return this; - } - - public List list() { - return getQuery().list(); - } - - public Object uniqueResult() { - return getQuery().uniqueResult(); - } - - public int executeUpdate() { - return getQuery().executeUpdate(); - } - - - public SQLQuery getQuery() { - return query; - } - - public void setQuery(SQLQuery query) { - this.query = query; - } - -} +//package com.percero.agents.sync.dao; +// +//import java.util.Collection; +//import java.util.Date; +//import java.util.List; +// +//import org.hibernate.SQLQuery; +// +//public class ActiveStackHibernateSqlQuery implements IActiveStackSqlQuery { +// +// private SQLQuery query; +// +// public ActiveStackHibernateSqlQuery(SQLQuery query) { +// this.query = query; +// } +// +// public String getQueryString() { +// return getQuery().getQueryString(); +// } +// +// @Override +// public String[] getNamedParameters() { +// return getQuery().getNamedParameters(); +// } +// +// public IActiveStackSqlQuery setString(int position, String val) { +// getQuery().setString(position, val); +// return this; +// } +// +// public IActiveStackSqlQuery setString(String name, String val) { +// getQuery().setString(name, val); +// return this; +// } +// +// public IActiveStackSqlQuery setDate(int position, Date val) { +// getQuery().setDate(position, val); +// return this; +// } +// +// public IActiveStackSqlQuery setDate(String name, Date val) { +// getQuery().setDate(name, val); +// return this; +// } +// +// public IActiveStackSqlQuery setParameter(int position, Object val) { +// getQuery().setParameter(position, val); +// return this; +// } +// +// public IActiveStackSqlQuery setParameter(String name, Object val) { +// getQuery().setParameter(name, val); +// return this; +// } +// +// public IActiveStackSqlQuery setParameterList(String name, Collection vals) { +// getQuery().setParameterList(name, vals); +// return this; +// } +// +// public IActiveStackSqlQuery setParameterList(String name, Object[] vals) { +// getQuery().setParameterList(name, vals); +// return this; +// } +// +// public List list() { +// return getQuery().list(); +// } +// +// public Object uniqueResult() { +// return getQuery().uniqueResult(); +// } +// +// public int executeUpdate() { +// return getQuery().executeUpdate(); +// } +// +// +// public SQLQuery getQuery() { +// return query; +// } +// +// public void setQuery(SQLQuery query) { +// this.query = query; +// } +// +//} diff --git a/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlSession.java b/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlSession.java index d6b7a6d..d2ad25f 100644 --- a/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlSession.java +++ b/src/main/java/com/percero/agents/sync/dao/ActiveStackHibernateSqlSession.java @@ -1,31 +1,31 @@ -package com.percero.agents.sync.dao; - -import org.hibernate.Session; - -public class ActiveStackHibernateSqlSession implements IActiveStackSqlSession { - - private Session session; - - public ActiveStackHibernateSqlSession(Session session) { - this.session = session; - } - - public IActiveStackSqlQuery createSQLQuery(String queryString) { - ActiveStackHibernateSqlQuery query = new ActiveStackHibernateSqlQuery(getSession().createSQLQuery(queryString)); - return query; - } - - public void close() { - if (getSession() != null) { - getSession().close(); - } - } - - public Session getSession() { - return session; - } - - public void setSession(Session session) { - this.session = session; - } -} +//package com.percero.agents.sync.dao; +// +//import org.hibernate.Session; +// +//public class ActiveStackHibernateSqlSession implements IActiveStackSqlSession { +// +// private Session session; +// +// public ActiveStackHibernateSqlSession(Session session) { +// this.session = session; +// } +// +// public IActiveStackSqlQuery createSQLQuery(String queryString) { +// ActiveStackHibernateSqlQuery query = new ActiveStackHibernateSqlQuery(getSession().createSQLQuery(queryString)); +// return query; +// } +// +// public void close() { +// if (getSession() != null) { +// getSession().close(); +// } +// } +// +// public Session getSession() { +// return session; +// } +// +// public void setSession(Session session) { +// this.session = session; +// } +//} diff --git a/src/main/java/com/percero/agents/sync/dao/ActiveStackMySQLDialect.java b/src/main/java/com/percero/agents/sync/dao/ActiveStackMySQLDialect.java new file mode 100644 index 0000000..deb38aa --- /dev/null +++ b/src/main/java/com/percero/agents/sync/dao/ActiveStackMySQLDialect.java @@ -0,0 +1,16 @@ +package com.percero.agents.sync.dao; + +import java.sql.Types; + +import org.hibernate.Hibernate; +import org.hibernate.dialect.MySQLDialect; + +public class ActiveStackMySQLDialect extends MySQLDialect { + + public ActiveStackMySQLDialect() { + super(); + + registerHibernateType(Types.LONGVARCHAR, Hibernate.TEXT.getName()); + } + +} diff --git a/src/main/java/com/percero/agents/sync/dao/ActiveStackSqlSessionFactory.java b/src/main/java/com/percero/agents/sync/dao/ActiveStackSqlSessionFactory.java index 5231c12..d5acfcc 100644 --- a/src/main/java/com/percero/agents/sync/dao/ActiveStackSqlSessionFactory.java +++ b/src/main/java/com/percero/agents/sync/dao/ActiveStackSqlSessionFactory.java @@ -1,38 +1,38 @@ -package com.percero.agents.sync.dao; - -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -import com.percero.agents.sync.exceptions.SyncDataException; - -@Component -public class ActiveStackSqlSessionFactory { - - private static ActiveStackSqlSessionFactory instance = null; - public static ActiveStackSqlSessionFactory getInstance() throws SyncDataException { - if (instance != null) { - return instance; - } - - throw new SyncDataException("No Session Factory", -1001); - } - - public ActiveStackSqlSessionFactory() { - ActiveStackSqlSessionFactory.instance = this; - } - - @Autowired - @Qualifier(value="appSessionFactory") - SessionFactory appSessionFactory; - public void setAppSessionFactory(SessionFactory value) { - appSessionFactory = value; - } - - public IActiveStackSqlSession retrieveOpenSession(String dataSource) { - ActiveStackHibernateSqlSession session = new ActiveStackHibernateSqlSession(appSessionFactory.openSession()); - return session; - } -} +//package com.percero.agents.sync.dao; +// +//import org.hibernate.Session; +//import org.hibernate.SessionFactory; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Qualifier; +//import org.springframework.stereotype.Component; +// +//import com.percero.agents.sync.exceptions.SyncDataException; +// +//@Component +//public class ActiveStackSqlSessionFactory { +// +// private static ActiveStackSqlSessionFactory instance = null; +// public static ActiveStackSqlSessionFactory getInstance() throws SyncDataException { +// if (instance != null) { +// return instance; +// } +// +// throw new SyncDataException("No Session Factory", -1001); +// } +// +// public ActiveStackSqlSessionFactory() { +// ActiveStackSqlSessionFactory.instance = this; +// } +// +// @Autowired +// @Qualifier(value="appSessionFactory") +// SessionFactory appSessionFactory; +// public void setAppSessionFactory(SessionFactory value) { +// appSessionFactory = value; +// } +// +// public IActiveStackSqlSession retrieveOpenSession(String dataSource) { +// ActiveStackHibernateSqlSession session = new ActiveStackHibernateSqlSession(appSessionFactory.openSession()); +// return session; +// } +//} diff --git a/src/main/java/com/percero/agents/sync/dao/DAORegistry.java b/src/main/java/com/percero/agents/sync/dao/DAORegistry.java new file mode 100644 index 0000000..ea590ff --- /dev/null +++ b/src/main/java/com/percero/agents/sync/dao/DAORegistry.java @@ -0,0 +1,39 @@ +package com.percero.agents.sync.dao; + +import java.util.HashMap; +import java.util.Map; + +import com.percero.agents.sync.services.DAODataProvider; +import com.percero.agents.sync.services.DataProviderManager; +import com.percero.framework.vo.IPerceroObject; + +import edu.emory.mathcs.backport.java.util.Collections; + +public class DAORegistry { + + private static DAORegistry instance = null; + + public static DAORegistry getInstance() { + if (instance == null) { + instance = new DAORegistry(); + } + return instance; + } + + public DAORegistry() { + instance = this; + + DataProviderManager.getInstance().addDataProvider(DAODataProvider.getInstance()); + } + + @SuppressWarnings({ "unchecked" }) + private static Map> dataAccessObjects = Collections.synchronizedMap(new HashMap>()); + + public void registerDataAccessObject(String name, IDataAccessObject dataAccessObject) { + dataAccessObjects.put(name, dataAccessObject); + } + + public IDataAccessObject getDataAccessObject(String name) { + return dataAccessObjects.get(name); + } +} diff --git a/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlQuery.java b/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlQuery.java index 400c960..fe7fd6e 100644 --- a/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlQuery.java +++ b/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlQuery.java @@ -1,23 +1,23 @@ -package com.percero.agents.sync.dao; - -import java.util.Collection; -import java.util.Date; -import java.util.List; - -public interface IActiveStackSqlQuery { - - public String getQueryString(); - public String[] getNamedParameters(); - public IActiveStackSqlQuery setString(int position, String val); - public IActiveStackSqlQuery setString(String name, String val); - public IActiveStackSqlQuery setDate(int position, Date val); - public IActiveStackSqlQuery setDate(String name, Date val); - public IActiveStackSqlQuery setParameter(int position, Object val); - public IActiveStackSqlQuery setParameter(String name, Object val); - public IActiveStackSqlQuery setParameterList(String name, Collection vals); - public IActiveStackSqlQuery setParameterList(String name, Object[] vals); - public List list(); - public Object uniqueResult(); - public int executeUpdate(); - -} +//package com.percero.agents.sync.dao; +// +//import java.util.Collection; +//import java.util.Date; +//import java.util.List; +// +//public interface IActiveStackSqlQuery { +// +// public String getQueryString(); +// public String[] getNamedParameters(); +// public IActiveStackSqlQuery setString(int position, String val); +// public IActiveStackSqlQuery setString(String name, String val); +// public IActiveStackSqlQuery setDate(int position, Date val); +// public IActiveStackSqlQuery setDate(String name, Date val); +// public IActiveStackSqlQuery setParameter(int position, Object val); +// public IActiveStackSqlQuery setParameter(String name, Object val); +// public IActiveStackSqlQuery setParameterList(String name, Collection vals); +// public IActiveStackSqlQuery setParameterList(String name, Object[] vals); +// public List list(); +// public Object uniqueResult(); +// public int executeUpdate(); +// +//} diff --git a/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlSession.java b/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlSession.java index afa874a..83a077e 100644 --- a/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlSession.java +++ b/src/main/java/com/percero/agents/sync/dao/IActiveStackSqlSession.java @@ -1,8 +1,8 @@ -package com.percero.agents.sync.dao; - -public interface IActiveStackSqlSession { - - public IActiveStackSqlQuery createSQLQuery(String queryString); - - public void close(); -} +//package com.percero.agents.sync.dao; +// +//public interface IActiveStackSqlSession { +// +// public IActiveStackSqlQuery createSQLQuery(String queryString); +// +// public void close(); +//} diff --git a/src/main/java/com/percero/agents/sync/dao/IDataAccessObject.java b/src/main/java/com/percero/agents/sync/dao/IDataAccessObject.java index 4f4914b..74d964e 100644 --- a/src/main/java/com/percero/agents/sync/dao/IDataAccessObject.java +++ b/src/main/java/com/percero/agents/sync/dao/IDataAccessObject.java @@ -18,20 +18,24 @@ public interface IDataAccessObject { Boolean hasUpdateAccess(ClassIDPair classIdPair, String userId); Boolean hasDeleteAccess(ClassIDPair classIdPair, String userId); - PerceroList getAll(Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception; + PerceroList getAll(Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId, Boolean shellOnly) throws Exception; + Integer countAll(String userId) throws SyncException; - List getAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException; + List retrieveAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException; - List findByExample(T theQueryObject, List excludeProperties) throws SyncException; + List findByExample(T theQueryObject, List excludeProperties, String userId, Boolean shellOnly) throws SyncException; T retrieveObject(ClassIDPair classIdPair, String userId, Boolean shellOnly) throws SyncException; List retrieveObjects(ClassIDPairs classIdPairs, String userId, Boolean shellOnly) throws SyncException; - Boolean createObject(T percero, String userIdObject) throws SyncException; + T createObject(T percero, String userIdObject) throws SyncException; - Boolean updateObject(T perceroObject, Map> changedFields, String userId) throws SyncException; + T updateObject(T perceroObject, Map> changedFields, String userId) throws SyncException; - Boolean deleteObject(ClassIDPair classIdPair, String userIdObject) throws SyncException; + Boolean deleteObject(ClassIDPair classIdPair, String userId) throws SyncException; + List runQuery(String queryName, Object[] queryArguments, String userId) throws SyncException; + T cleanObjectForUser(T perceroObject, + String userId); } diff --git a/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java b/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java index c82acf3..06666ea 100644 --- a/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java +++ b/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java @@ -45,10 +45,10 @@ public abstract void setValues( public abstract Long lpushListValue(String key, Object value); @Transactional - public abstract List listAll(String key); + public abstract List listAll(String key); @Transactional - public abstract List listRange(String key, Long start, Long end); + public abstract List listRange(String key, Long start, Long end); @Transactional public abstract Object listIndex(String key, Long index); @@ -60,16 +60,16 @@ public abstract void setValues( public abstract Object getHashValue(String key, String hashKey); @Transactional - public abstract Set getHashKeys(String key); + public abstract Set getHashKeys(String key); @Transactional - public abstract Map getHashEntries(String key); + public abstract Map getHashEntries(String key); @Transactional public abstract Long getHashSize(String key); @Transactional - public abstract void deleteHashKey(String key, Object hashKey); + public abstract void deleteHashKey(String key, String hashKey); @Transactional public abstract void setHashValue(String key, String hashKey, Object value); diff --git a/src/main/java/com/percero/agents/sync/datastore/JedisCacheDataStore.java b/src/main/java/com/percero/agents/sync/datastore/JedisCacheDataStore.java new file mode 100644 index 0000000..647f21a --- /dev/null +++ b/src/main/java/com/percero/agents/sync/datastore/JedisCacheDataStore.java @@ -0,0 +1,648 @@ +//package com.percero.agents.sync.datastore; +// +//import java.util.ArrayList; +//import java.util.Collection; +//import java.util.HashMap; +//import java.util.HashSet; +//import java.util.Iterator; +//import java.util.List; +//import java.util.Map; +//import java.util.Map.Entry; +//import java.util.Set; +//import java.util.concurrent.TimeUnit; +// +//import org.apache.log4j.Logger; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.data.redis.core.HashOperations; +//import org.springframework.data.redis.core.RedisTemplate; +//import org.springframework.data.redis.core.SetOperations; +//import org.springframework.scheduling.annotation.Scheduled; +//import org.springframework.stereotype.Component; +//import org.springframework.transaction.annotation.Transactional; +// +//import redis.clients.jedis.HostAndPort; +//import redis.clients.jedis.JedisCluster; +// +//import com.percero.agents.sync.services.PerceroRedisTemplate; +// +//import edu.emory.mathcs.backport.java.util.Collections; +// +//@Component +//public class JedisCacheDataStore implements ICacheDataStore { +// +// private static Logger log = Logger.getLogger(JedisCacheDataStore.class); +// +// JedisCluster jc = null; +// +// public void init() { +// Set jedisClusterNodes = new HashSet(); +// //Jedis Cluster will attempt to discover cluster nodes automatically +// jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379)); +// jc = new JedisCluster(jedisClusterNodes); +// jc.set("foo", "bar"); +// String value = jc.get("foo"); +// +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.lang.String, long, java.util.concurrent.TimeUnit) +// */ +// @Override +// public Boolean expire( final String key, final long timeout, final TimeUnit timeUnit ) { +// return expire(key, timeout, timeUnit, false); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.util.Collection, long, java.util.concurrent.TimeUnit) +// */ +// @Override +// public Boolean expire( final Collection keys, final long timeout, final TimeUnit timeUnit ) { +// return expire(keys, timeout, timeUnit, false); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.lang.String, long, java.util.concurrent.TimeUnit, java.lang.Boolean) +// */ +// @Override +// public Boolean expire( final String key, final long timeout, final TimeUnit timeUnit, Boolean forceNow ) { +// if (forceNow) { +// Long numSeconds = timeUnit.convert(timeout, TimeUnit.SECONDS); +// return jc.expire(key, numSeconds.intValue()) > 0; +// } +// else { +// expiresToBeWritten.put(key, new PendingExpire(key, timeout, timeUnit)); +// return true; +// } +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.util.Collection, long, java.util.concurrent.TimeUnit, java.lang.Boolean) +// */ +// @Override +// public Boolean expire( final Collection keys, final long timeout, final TimeUnit timeUnit, Boolean forceNow ) { +// if (forceNow) { +// Iterator itrKeys = keys.iterator(); +// while (itrKeys.hasNext()) { +// Long numSeconds = timeUnit.convert(timeout, TimeUnit.SECONDS); +// if ( jc.expire(itrKeys.next(), numSeconds.intValue()) <= 0 ) { +// return false; +// } +// } +// return true; +// } +// else { +// Iterator itrKeys = keys.iterator(); +// while (itrKeys.hasNext()) { +// String nextKey = itrKeys.next(); +// expiresToBeWritten.put(nextKey, new PendingExpire(nextKey, timeout, timeUnit)); +// } +// return true; +// } +// } +// +// +// @SuppressWarnings("unchecked") +// private Map expiresToBeWritten = Collections.synchronizedMap(new HashMap()); +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#postExpires() +// */ +// @Override +// @Scheduled(fixedRate=600000) // 10 * 60 * 1000 -> Ten Minutes. +// public void postExpires() { +// log.info("Posting " + expiresToBeWritten.size() + " expire" + (expiresToBeWritten.size() == 1 ? "" : "s")); +// synchronized (expiresToBeWritten) { +// Collection expireKeysToRemove = new HashSet(expiresToBeWritten.size(), (float)1.0); +// Iterator> itrExpiresEntrySet = expiresToBeWritten.entrySet().iterator(); +// while (itrExpiresEntrySet.hasNext()) { +// Map.Entry nextEntry = itrExpiresEntrySet.next(); +// String nextKey = nextEntry.getKey(); +// PendingExpire nextPendingExpire = nextEntry.getValue(); +// expire(nextPendingExpire.key, nextPendingExpire.timeout, nextPendingExpire.timeUnit, true); +// expireKeysToRemove.add(nextKey); +// } +//// Iterator itrExpires = expiresToBeWritten.keySet().iterator(); +//// while (itrExpires.hasNext()) { +//// String nextKey = itrExpires.next(); +//// PendingExpire nextPendingExpire = expiresToBeWritten.get(nextKey); +//// expire(nextPendingExpire.key, nextPendingExpire.timeout, nextPendingExpire.timeUnit, true); +//// expireKeysToRemove.add(nextKey); +//// } +// +// Iterator itrExpireKeysToRemove = expireKeysToRemove.iterator(); +// while (itrExpireKeysToRemove.hasNext()) { +// expiresToBeWritten.remove(itrExpireKeysToRemove.next()); +// } +// } +// } +// +// private class PendingExpire { +// String key; +// long timeout; +// TimeUnit timeUnit; +// +// public PendingExpire(String key, long timeout, TimeUnit timeUnit) { +// this.key = key; +// this.timeout = timeout; +// this.timeUnit = timeUnit; +// } +// } +// +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getValue(java.lang.String) +// */ +// @Override +// public Object getValue( final String key ) { +// return jc.get( key ); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getValues(java.util.Collection) +// */ +// @Override +// public List getValues( final Collection keys ) { +// List result = new ArrayList(); +// if (keys != null) { +// Iterator itrKeys = keys.iterator(); +// while (itrKeys.hasNext()) { +// String nextKey = itrKeys.next(); +// String nextValue = jc.get(nextKey); +// if (nextValue != null) { +// result.add(nextValue); +// } +// } +// } +// +// return result; +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setValue(java.lang.String, java.lang.Object) +// */ +// @Override +// public void setValue( final String key, final Object value ) { +// jc.set( key, (String) value ); +// } +// +//// public void setValues( final KeyValuePair[] pairs ) { +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setValues(java.util.Map) +// */ +// @SuppressWarnings("unchecked") +// @Override +// public void setValues( final Map keysAndValuesMap ) { +// +// if (keysAndValuesMap != null) { +// Iterator itrKeysAndValuesMap = keysAndValuesMap.entrySet().iterator(); +// while (itrKeysAndValuesMap.hasNext()) { +// Entry nextEntry = (Entry) itrKeysAndValuesMap.next(); +// jc.set(nextEntry.getKey(), (String) nextEntry.getValue()); +// } +// } +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#addSetValue(java.lang.String, java.lang.Object) +// */ +// @Override +// @Transactional +// public Long addSetValue( final String key, final Object value ) { +// return jc.sadd(key, (String) value);// ? Long.valueOf(1) : Long.valueOf(0); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#lpushListValue(java.lang.String, java.lang.Object) +// */ +// @Override +// @Transactional +// public Long lpushListValue( final String key, final Object value ) { +// return jc.lpush(key, (String) value); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listAll(java.lang.String) +// */ +// @Override +// @Transactional +// public List listAll( final String key) { +// return listRange(key, Long.valueOf(0), Long.valueOf(-1)); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listRange(java.lang.String, java.lang.Long, java.lang.Long) +// */ +// @Override +// @Transactional +// public List listRange( final String key, final Long start, final Long end ) { +// return jc.lrange(key, start, end); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listIndex(java.lang.String, java.lang.Long) +// */ +// @Override +// @Transactional +// public Object listIndex( final String key, final Long index ) { +// return jc.lindex(key, index); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listIndex(java.lang.String) +// */ +// @Override +// @Transactional +// public Object listIndex( final String key ) { +// return jc.lindex(key, Long.valueOf(0)); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashValue(java.lang.String, java.lang.String) +// */ +// @Override +// @Transactional +// public Object getHashValue( final String key, final String hashKey ) { +// return jc.hget(key, hashKey); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashKeys(java.lang.String) +// */ +// @Override +// @Transactional +// public Set getHashKeys( final String key ) { +// return jc.hkeys(key); +// } +// +//// /* (non-Javadoc) +//// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashEntries(java.lang.String) +//// */ +//// @Override +//// @Transactional +//// public Map getHashEntries( final String key ) { +//// return jc.hmget(getHashKeys(key)); +//// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashSize(java.lang.String) +// */ +// @Override +// @Transactional +// public Long getHashSize( final String key ) { +// return jc.hlen(key); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#deleteHashKey(java.lang.String, java.lang.Object) +// */ +// @Override +// @Transactional +// public void deleteHashKey( final String key, final String hashKey ) { +// jc.hdel(key, hashKey); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setHashValue(java.lang.String, java.lang.String, java.lang.Object) +// */ +// @Override +// @Transactional +// public void setHashValue( final String key, final String hashKey, final Object value ) { +// jc.hset(key, hashKey, (String) value); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setAllHashValues(java.lang.String, java.util.Map) +// */ +// @Override +// @Transactional +// public void setAllHashValues( final String key, final Map hashMap ) { +// jc.hsetAll(key, hashMap); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetValue(java.lang.String, java.lang.Object) +// */ +// @Override +// @Transactional +// public Long removeSetValue( final String key, final Object value ) { +// return template.opsForSet().remove(key, value);// ? Long.valueOf(1) : Long.valueOf(0); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIsEmpty(java.lang.String) +// */ +// @Override +// @Transactional +// public Boolean getSetIsEmpty( final String key ) { +// Long result = template.opsForSet().size(key);// ? Long.valueOf(1) : Long.valueOf(0); +// return (result <= 0); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetValueAndGetSize(java.lang.String, java.lang.Object) +// */ +// @Override +// @Transactional +// public Long removeSetValueAndGetSize( final String key, final Object value ) { +// SetOperations setOps = template.opsForSet(); +// setOps.remove(key, value); +// return setOps.size(key); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetsValue(java.util.Collection, java.lang.Object) +// */ +// @Override +// public void removeSetsValue( final Collection keys, final Object value ) { +// SetOperations setOps = template.opsForSet(); +// Iterator itrKeys = keys.iterator(); +// while(itrKeys.hasNext()) { +// Object nextKey = itrKeys.next(); +// try { +// setOps.remove((String) nextKey, value); +// } catch(Exception e) { +// log.warn("Invalid Key", e); +// } +// } +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetsValue(java.lang.String, java.util.Collection, java.lang.Object) +// */ +// @Override +// public void removeSetsValue( final String keysPrefix, final Collection keys, final Object value ) { +// SetOperations setOps = template.opsForSet(); +// Iterator itrKeys = keys.iterator(); +// while(itrKeys.hasNext()) { +// Object nextKey = itrKeys.next(); +// try { +// setOps.remove(keysPrefix + (String) nextKey, value); +// } catch(Exception e) { +// log.warn("Invalid Key", e); +// } +// } +// } +// +//// private static long keysCount = 0; +//// public Set keys(String pattern) { +//// Set result = template.keys(pattern); +//// log.info("Keys: " + ++keysCount); +//// +//// return result; +//// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#hasKey(java.lang.String) +// */ +// @Override +// public Boolean hasKey(String key) { +// Boolean result = template.hasKey(key); +// return result; +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#hasHashKey(java.lang.String, java.lang.String) +// */ +// @Override +// public Boolean hasHashKey(String key, String hashKey) { +// Boolean result = template.opsForHash().hasKey(key, hashKey); +// return result; +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#swapHashKey(java.lang.String, java.lang.String, java.lang.String) +// */ +// @Override +// @Transactional +// public void swapHashKey( final String key, final String oldHashKey, final String newHashValue ) { +// HashOperations hashOps = template.opsForHash(); +// if (hashOps.hasKey(key, oldHashKey)) { +// hashOps.put(key, newHashValue, hashOps.get(key, oldHashKey)); +// hashOps.delete(key, oldHashKey); +// } +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#renameIfAbsent(java.lang.String, java.lang.String) +// */ +// @Override +// public Boolean renameIfAbsent(String oldKey, String newKey) { +// return template.renameIfAbsent(oldKey, newKey); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#rename(java.lang.String, java.lang.String) +// */ +// @Override +// public void rename(String oldKey, String newKey) { +// template.rename(oldKey, newKey); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setUnionAndStore(java.lang.String, java.lang.String, java.lang.String) +// */ +// @Override +// public Long setUnionAndStore(String key, String otherKey, String destKey) { +// return template.opsForSet().unionAndStore(key, otherKey, destKey); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setUnionAndStore(java.lang.String, java.util.Collection, java.lang.String) +// */ +// @Override +// public Long setUnionAndStore(String key, Collection otherKeys, String destKey) { +// return template.opsForSet().unionAndStore(key, otherKeys, destKey); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisDataStore#removeSetValues(java.lang.String, java.util.Collection) +// */ +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetValues(java.lang.String, java.util.Collection) +// */ +// @Override +// @Transactional +// public void removeSetValues( final String key, final Collection values ) { +// SetOperations setOps = template.opsForSet(); +// +// Iterator itrValues = values.iterator(); +// while(itrValues.hasNext()) { +// try { +// setOps.remove(key, itrValues.next()); +// } catch(Exception e) { +// log.error("Unable to remove Set Value", e); +// } +// } +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetValue(java.lang.String) +// */ +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetValue(java.lang.String) +// */ +// @Override +// public Set getSetValue( final String key ) { +// return template.opsForSet().members(key); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#replaceSet(java.lang.String, java.util.Collection) +// */ +// @Override +// @Transactional +// public Long replaceSet( final String key, Collection values ) { +// template.delete(key); +// if (values != null) { +// return template.opsForSet().add(key, values.toArray()); +// } +// else { +// return Long.valueOf(0); +// } +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisDataStore#swapSetValue(java.lang.String, java.lang.String, java.lang.String) +// */ +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#swapSetValue(java.lang.String, java.lang.String, java.lang.String) +// */ +// @Override +// @Transactional +// public void swapSetValue( final String key, final String oldValue, final String newValue ) { +// SetOperations setOps = template.opsForSet(); +// if (setOps.isMember(key, oldValue)) { +// setOps.remove(key, oldValue); +// setOps.add(key, newValue); +// } +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIsMember(java.lang.String, java.lang.Object) +// */ +// @Override +// public Boolean getSetIsMember( final String key, final Object object ) { +// return template.opsForSet().isMember(key, object); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetsContainsMembers(java.util.Collection, java.lang.Object[]) +// */ +// @Override +// @Transactional +// public Set getSetsContainsMembers( final Collection keys, final Object[] membersToCheck ) { +// SetOperations setOps = template.opsForSet(); +// String randomKey = "UserTokenCheck:" + System.currentTimeMillis(); +// setOps.add(randomKey, membersToCheck); +// +// Set intersectingMembers = new HashSet(); +// Iterator itrKeys = keys.iterator(); +// while (itrKeys.hasNext()) { +// String nextKey = itrKeys.next(); +// intersectingMembers.addAll(setOps.intersect(randomKey, nextKey)); +// } +// template.delete(randomKey); +// return intersectingMembers; +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIntersect(java.lang.String, java.util.Collection) +// */ +// @Override +// public Set getSetIntersect( final String key, Collection otherKeys ) { +// return template.opsForSet().intersect(key, otherKeys); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIntersect(java.lang.String, java.lang.String) +// */ +// @Override +// public Set getSetIntersect( final String key, String otherKey ) { +// return template.opsForSet().intersect(key, otherKey); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetUnion(java.lang.String, java.util.Collection) +// */ +// @Override +// public Set getSetUnion( final String key, final Collection otherKeys ) { +// return template.opsForSet().union(key, otherKeys); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetUnion(java.lang.String, java.lang.String) +// */ +// @Override +// public Set getSetUnion( final String key, final String otherKey ) { +// return template.opsForSet().union(key, otherKey); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#deleteKey(java.lang.String) +// */ +// @Override +// public void deleteKey( final String key ) { +// template.delete(key); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#deleteKeys(java.util.Collection) +// */ +// @Override +// public void deleteKeys( final Collection keys ) { +// if (keys != null && !keys.isEmpty()) { +// template.delete(keys); +// } +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setSetValue(java.lang.String, java.lang.Object) +// */ +// @Override +// @Transactional +// public Long setSetValue(String key, Object value) { +// return template.opsForSet().add(key, value);// ? Long.valueOf(1) : Long.valueOf(0); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSet(java.lang.String) +// */ +// @Override +// public SetOperations getSet(String key) { +// return template.opsForSet(); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getTemplate() +// */ +// @Override +// public RedisTemplate getTemplate() { +// return template; +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#keys(java.lang.String) +// */ +// @Override +// public Collection keys(String pattern) { +// return template.keys(pattern); +// } +// +// /* (non-Javadoc) +// * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeKeysValue(java.lang.String, java.lang.Object) +// */ +// @Override +// @Transactional +// public void removeKeysValue(String pattern, Object value) { +// Set keys = template.keys(pattern); +// Iterator itrKeys = keys.iterator(); +// +// while(itrKeys.hasNext()) { +// try { +// template.opsForSet().remove(itrKeys.next(), value); +// } catch(Exception e) { +// log.error("Error removing KeysValue", e); +// } +// } +// } +// +//} diff --git a/src/main/java/com/percero/agents/sync/datastore/RedisCacheDataStore.java b/src/main/java/com/percero/agents/sync/datastore/RedisCacheDataStore.java index 8b28621..a5b7ce0 100644 --- a/src/main/java/com/percero/agents/sync/datastore/RedisCacheDataStore.java +++ b/src/main/java/com/percero/agents/sync/datastore/RedisCacheDataStore.java @@ -6,6 +6,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -236,8 +237,13 @@ public Object getHashValue( final String key, final String hashKey ) { */ @Override @Transactional - public Set getHashKeys( final String key ) { - return template.opsForHash().keys(key); + public Set getHashKeys( final String key ) { + Set keysObjects = template.opsForHash().keys(key); + Set results = new HashSet(keysObjects.size()); + for(Object nextKey : keysObjects) { + results.add((String)nextKey); + } + return results; } /* (non-Javadoc) @@ -245,8 +251,15 @@ public Set getHashKeys( final String key ) { */ @Override @Transactional - public Map getHashEntries( final String key ) { - return template.opsForHash().entries(key); + public Map getHashEntries( final String key ) { + Map entries = template.opsForHash().entries(key); + Map result = new HashMap(); + Iterator> itrEntries = entries.entrySet().iterator(); + while (itrEntries.hasNext()) { + Entry nextEntry = itrEntries.next(); + result.put((String) nextEntry.getKey(), nextEntry.getValue()); + } + return result; } /* (non-Javadoc) @@ -263,7 +276,7 @@ public Long getHashSize( final String key ) { */ @Override @Transactional - public void deleteHashKey( final String key, final Object hashKey ) { + public void deleteHashKey( final String key, final String hashKey ) { template.opsForHash().delete(key, hashKey); } diff --git a/src/main/java/com/percero/agents/sync/exceptions/SyncException.java b/src/main/java/com/percero/agents/sync/exceptions/SyncException.java index d3ed1ca..2894a78 100644 --- a/src/main/java/com/percero/agents/sync/exceptions/SyncException.java +++ b/src/main/java/com/percero/agents/sync/exceptions/SyncException.java @@ -14,6 +14,10 @@ public class SyncException extends Exception { public static final Integer RUN_PROCESS_ERROR_CODE = -103; public static final String MISSING_MAPPED_CLASS_ERROR = "missingMappedClass"; public static final Integer MISSING_MAPPED_CLASS_ERROR_CODE = -104; + public static final String METHOD_UNSUPPORTED = "methodUnsupported"; + public static final Integer METHOD_UNSUPPORTED_CODE = -105; + public static final String METHOD_NOT_IMPLEMENTED = "methodNotImplemented"; + public static final Integer METHOD_NOT_IMPLEMENTED_CODE = -106; public SyncException(String name, Integer code, String desc, Throwable t) { diff --git a/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java b/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java index 117877e..50c5a0d 100644 --- a/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java @@ -4,9 +4,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.log4j.Logger; import org.codehaus.jackson.map.ObjectMapper; @@ -132,7 +130,7 @@ public void pushObjectUpdateJournals(Collection clientIds, ClassIDPair c PushUpdateResponse pushUpdateResponse = new PushUpdateResponse(); pushUpdateResponse.setObjectList(new ArrayList()); - BaseDataObject object = dataProvider.systemGetById(classIdPair); + BaseDataObject object = (BaseDataObject) dataProvider.findById(classIdPair, null); if (object != null) { pushUpdateResponse.getObjectList().add(object); diff --git a/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java b/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java index dca6fe0..000f027 100644 --- a/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java @@ -64,10 +64,10 @@ public void postClient(String clientId) throws Exception { // Timeout Client's UserDevice. // Collection userDeviceKeys = redisDataStore.keys(RedisKeyUtils.userDevice(userId, "*")); // TODO: This expire no longer works!!! - Collection userDeviceKeys = cacheDataStore.getHashKeys(RedisKeyUtils.userDeviceHash(userId)); - Iterator itrUserDevices = userDeviceKeys.iterator(); + Collection userDeviceKeys = cacheDataStore.getHashKeys(RedisKeyUtils.userDeviceHash(userId)); + Iterator itrUserDevices = userDeviceKeys.iterator(); while (itrUserDevices.hasNext()) { - String nextKey = (String) itrUserDevices.next(); + String nextKey = itrUserDevices.next(); if (clientId.equals(cacheDataStore.getValue(nextKey))) { cacheDataStore.expire(RedisKeyUtils.deviceHash(nextKey), userDeviceTimeout, TimeUnit.SECONDS); cacheDataStore.expire(nextKey, userDeviceTimeout, TimeUnit.SECONDS); diff --git a/src/main/java/com/percero/agents/sync/hibernate/SyncHibernateUtils.java b/src/main/java/com/percero/agents/sync/hibernate/SyncHibernateUtils.java index ac32a24..7175938 100644 --- a/src/main/java/com/percero/agents/sync/hibernate/SyncHibernateUtils.java +++ b/src/main/java/com/percero/agents/sync/hibernate/SyncHibernateUtils.java @@ -613,7 +613,7 @@ private static boolean hasAccess(Object ob, String userId, IMappedClassManager m if (isValidReadQuery) { // There is a ReadQuery, so process that. Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, ob, userId); + mappedClass.getReadQuery().setQueryParameters(readFilter.getQueryString(), ob, userId); Number readFilterResult = (Number) readFilter.uniqueResult(); if (readFilterResult == null || readFilterResult.intValue() <= 0) hasAccess = false; @@ -639,7 +639,7 @@ private static boolean hasFieldAccess(Object ob, String userId, MappedField mapp ob = getShell(ob); // There is a ReadQuery, so process that. Query readFilter = s.createQuery(mappedField.getReadQuery().getQuery()); - mappedField.getReadQuery().setQueryParameters(readFilter, ob, userId); + mappedField.getReadQuery().setQueryParameters(readFilter.getQueryString(), ob, userId); Number readFilterResult = (Number) readFilter.uniqueResult(); if (readFilterResult == null || readFilterResult.intValue() <= 0) hasAccess = false; diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java index 65e5e5e..3750446 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java @@ -1,50 +1,50 @@ -package com.percero.agents.sync.jobs; - -import com.mchange.v2.c3p0.ComboPooledDataSource; -import org.apache.log4j.Logger; -import org.hibernate.SessionFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -/** - * Created by jonnysamps on 8/31/15. - */ -@Component -public class UpdateTablePoller { - - private static Logger logger = Logger.getLogger(UpdateTablePoller.class); - - private String[] tableNames = new String[0]; - @Autowired - @Value("$pf{updateTable.tableNames}") - public void setTableNames(String val){ - tableNames = val.split(","); - } - - - @Autowired - UpdateTableConnectionFactory connectionFactory; - - /** - * Run every minute - */ - @Scheduled(fixedDelay=6000, initialDelay=6000) - public void pollUpdateTables(){ - logger.info("Polling Update Tables..."); - for(String tableName : tableNames){ - UpdateTableProcessor processor = new UpdateTableProcessor(tableName, connectionFactory); - ProcessorResult result = processor.process(); - if(result.isSuccess()){ - logger.debug("Update table processor ("+tableName+") finished successfully. Total rows ("+result.getTotal()+")"); - } - else{ - logger.warn("Update table processor ("+tableName+") failed. Details:"); - logger.warn(result); - } - } - } - - -} +//package com.percero.agents.sync.jobs; +// +//import com.mchange.v2.c3p0.ComboPooledDataSource; +//import org.apache.log4j.Logger; +//import org.hibernate.SessionFactory; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.scheduling.annotation.Scheduled; +//import org.springframework.stereotype.Component; +// +///** +// * Created by jonnysamps on 8/31/15. +// */ +//@Component +//public class UpdateTablePoller { +// +// private static Logger logger = Logger.getLogger(UpdateTablePoller.class); +// +// private String[] tableNames = new String[0]; +// @Autowired +// @Value("$pf{updateTable.tableNames}") +// public void setTableNames(String val){ +// tableNames = val.split(","); +// } +// +// +// @Autowired +// UpdateTableConnectionFactory connectionFactory; +// +// /** +// * Run every minute +// */ +// @Scheduled(fixedDelay=6000, initialDelay=6000) +// public void pollUpdateTables(){ +// logger.info("Polling Update Tables..."); +// for(String tableName : tableNames){ +// UpdateTableProcessor processor = new UpdateTableProcessor(tableName, connectionFactory); +// ProcessorResult result = processor.process(); +// if(result.isSuccess()){ +// logger.debug("Update table processor ("+tableName+") finished successfully. Total rows ("+result.getTotal()+")"); +// } +// else{ +// logger.warn("Update table processor ("+tableName+") failed. Details:"); +// logger.warn(result); +// } +// } +// } +// +// +//} diff --git a/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java b/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java index 264ceb2..90e94cd 100644 --- a/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java +++ b/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java @@ -1,10 +1,24 @@ package com.percero.agents.sync.metadata; +import java.util.Date; +import java.util.Iterator; +import java.util.Map; + +import org.apache.log4j.Logger; import org.hibernate.Query; +import org.hibernate.engine.query.NamedParameterDescriptor; +import org.hibernate.engine.query.ParameterMetadata; +import org.hibernate.impl.SessionFactoryImpl; import org.hibernate.impl.SessionImpl; +import org.hibernate.type.TimestampType; +import org.hibernate.type.Type; public class JpqlQuery extends MappedQuery { + private static final Logger log = Logger.getLogger(JpqlQuery.class); + + private ParameterMetadata parameterMetadata = null; + @Override public void setQuery(String value) { int index = value.indexOf("jpql:"); @@ -13,11 +27,76 @@ public void setQuery(String value) { super.setQuery(value); } - @Override public Query createQuery(Object theObject, String userId, Object[] params, SessionImpl s) throws Exception { - Query theQuery = s.createQuery(getQuery()); - setQueryParameters(theQuery, theObject, userId, params, s); + String queryString = getQuery(); + queryString = setQueryParameters(queryString, theObject, userId, params); + queryString = setParameterMetadata(queryString, theObject, userId, params, s); + Query theQuery = s.createQuery(queryString); + + return theQuery; + } + + private String setParameterMetadata(String theQuery, Object theObject, String userId, Object[] params, SessionImpl s) { + // Get Parameter MetaData. + if (params != null && params.length > 0) { + if (parameterMetadata == null) { + try { + parameterMetadata = ((SessionFactoryImpl)s.getSessionFactory()).getQueryPlanCache().getHQLQueryPlan(theQuery, false, (s).getEnabledFilters()).getParameterMetadata(); + } catch(Exception e) { + log.warn("Unable to get ParameterMetaData from Query:\n" + theQuery, e); + } + } + + for(Object nextParam : params) { + if (nextParam instanceof Map) { + Map nextMapParam = (Map) nextParam; + Iterator itr = nextMapParam.entrySet().iterator(); + while(itr.hasNext()) { + Boolean paramSet = false; + try { + Map.Entry pairs = (Map.Entry) itr.next(); + Object key = pairs.getKey(); + Object value = pairs.getValue(); + + if (key instanceof String) { + String strKey = (String) key; + if (parameterMetadata != null) { + NamedParameterDescriptor npd = parameterMetadata.getNamedParameterDescriptor(strKey); + if (npd != null) { + Type expectedType = npd.getExpectedType(); + + if (expectedType instanceof TimestampType) { + Date dateValue = new Date((Long)value); + theQuery = theQuery.replaceAll(":" + strKey, "'" + dateValue + "'"); + } else { + theQuery = theQuery.replaceAll(":" + (String) key, "\"" + value + "\""); + } + paramSet = true; + } + } + + // Last ditch effort to set this parameter. + if (!paramSet) + theQuery = theQuery.replaceAll(":" + (String) key, "\"" + value + "\""); + } + } catch(Exception e) { + log.warn("Unable to apply parameter to filter", e); + } + } + } else if (nextParam instanceof String) { + String nextStringParam = (String) nextParam; + try { + String[] paramSplit = nextStringParam.split(":"); + String key = paramSplit[0]; + String value = paramSplit[1]; + theQuery = theQuery.replaceAll(":" + key, "\"" + value + "\""); + } catch(Exception e) { + log.warn("Unable to apply parameter to filter", e); + } + } + } + } return theQuery; } diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedClass.java b/src/main/java/com/percero/agents/sync/metadata/MappedClass.java index 8cdb5db..2a8e865 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedClass.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedClass.java @@ -216,7 +216,7 @@ public List getChildMappedClasses() { IDataProvider dataProvider = null; public IDataProvider getDataProvider() { if (dataProvider == null) { - dataProvider = DataProviderManager.dataProviderManager.getDataProviderByName(dataProviderName); + dataProvider = DataProviderManager.getInstance().getDataProviderByName(dataProviderName); } return dataProvider; } diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java b/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java index fc18896..7b990bd 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java @@ -1,17 +1,13 @@ package com.percero.agents.sync.metadata; import java.util.ArrayList; -import java.util.Date; +import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; -import org.hibernate.engine.query.NamedParameterDescriptor; import org.hibernate.engine.query.ParamLocationRecognizer; -import org.hibernate.engine.query.ParameterMetadata; -import org.hibernate.type.TimestampType; -import org.hibernate.type.Type; import org.springframework.util.StringUtils; import com.percero.framework.metadata.IMappedQuery; @@ -87,8 +83,7 @@ public String setQueryParameters(String theQuery, Object theObject, String userI @SuppressWarnings("rawtypes") public String setQueryParameters(String theQuery, Object theObject, String userId, Object[] params) throws Exception { - if (!queryParameterNamesSet) - { + if (!queryParameterNamesSet) { useUserId = theQuery.contains(":userId"); useId = theQuery.contains(":id"); useIds = theQuery.contains(":ids"); @@ -151,11 +146,10 @@ else if (theObject instanceof IPerceroObject) { log.warn("Unable to set IDs for MappedQuery from IPerceroObject"); } } - else if (theObject instanceof Object[]) - { + else if (theObject instanceof Object[]) { Object[] theObjectArray = (Object[]) theObject; - Collection idsList = new HashSet(theObjectArray.length); + String idsListString = null; for(Object nextParam : theObjectArray) { if (nextParam instanceof String) { @@ -163,7 +157,13 @@ else if (theObject instanceof Object[]) String[] nextParamSplit = ((String) nextParam).split(":"); if (nextParamSplit.length == 2) { if (nextParamSplit[0].equalsIgnoreCase("id")) { - idsList.add(nextParamSplit[1]); + if (idsListString != null) { + idsListString += ","; + } + else { + idsListString = ""; + } + idsListString += nextParamSplit[1]; break; } } @@ -173,20 +173,25 @@ else if (theObject instanceof Object[]) } else if (nextParam instanceof IPerceroObject) { try { - idsList.add(((IPerceroObject)nextParam).getID()); + if (idsListString != null) { + idsListString += ","; + } + else { + idsListString = ""; + } + idsListString += ((IPerceroObject)nextParam).getID(); } catch(Exception e) { log.warn("Unable to set IDs for MappedQuery from IPerceroObject"); } } } - theQuery.setParameterList("ids", idsList); + theQuery = theQuery.replaceAll(":ids", idsListString); } - else if (theObject instanceof Collection) - { + else if (theObject instanceof Collection) { Collection theObjectCollection = (Collection) theObject; - Collection idsList = new HashSet(theObjectCollection.size()); + String idsListString = null; for(Object nextParam : theObjectCollection) { if (nextParam instanceof String) { @@ -194,7 +199,13 @@ else if (theObject instanceof Collection) String[] nextParamSplit = ((String) nextParam).split(":"); if (nextParamSplit.length == 2) { if (nextParamSplit[0].equalsIgnoreCase("id")) { - idsList.add(nextParamSplit[1]); + if (idsListString != null) { + idsListString += ","; + } + else { + idsListString = ""; + } + idsListString += nextParamSplit[1]; break; } } @@ -204,14 +215,20 @@ else if (theObject instanceof Collection) } else if (nextParam instanceof IPerceroObject) { try { - idsList.add(((IPerceroObject)nextParam).getID()); + if (idsListString != null) { + idsListString += ","; + } + else { + idsListString = ""; + } + idsListString += ((IPerceroObject)nextParam).getID(); } catch(Exception e) { log.warn("Unable to set IDs for MappedQuery from IPerceroObject"); } } } - theQuery.setParameterList("ids", idsList); + theQuery = theQuery.replaceAll(":ids", idsListString); } } if (useUserId) { @@ -222,66 +239,6 @@ else if (nextParam instanceof IPerceroObject) { } } - // Get Parameter MetaData. - if (params != null && params.length > 0) { -// if (parameterMetadata == null) { -// try { -// parameterMetadata = ((SessionFactoryImpl)s.getSessionFactory()).getQueryPlanCache().getHQLQueryPlan(theQuery.getQueryString(), false, (s).getEnabledFilters()).getParameterMetadata(); -// } catch(Exception e) { -// log.warn("Unable to get ParameterMetaData from Query:\n" + theQuery.getQueryString(), e); -// } -// } - - for(Object nextParam : params) { - if (nextParam instanceof Map) { - Map nextMapParam = (Map) nextParam; - Iterator itr = nextMapParam.entrySet().iterator(); - while(itr.hasNext()) { - Boolean paramSet = false; - try { - Map.Entry pairs = (Map.Entry) itr.next(); - Object key = pairs.getKey(); - Object value = pairs.getValue(); - - if (key instanceof String) { - String strKey = (String) key; - if (parameterMetadata != null) { - NamedParameterDescriptor npd = parameterMetadata.getNamedParameterDescriptor(strKey); - if (npd != null) { - Type expectedType = npd.getExpectedType(); - - if (expectedType instanceof TimestampType) { - Date dateValue = new Date((Long)value); - theQuery = theQuery.replaceAll(":" + strKey, "'" + dateValue + "'"); - } else { - theQuery = theQuery.replaceAll(":" + (String) key, "\"" + value + "\""); - } - paramSet = true; - } - } - - // Last ditch effort to set this parameter. - if (!paramSet) - theQuery = theQuery.replaceAll(":" + (String) key, "\"" + value + "\""); - } - } catch(Exception e) { - log.warn("Unable to apply parameter to filter", e); - } - } - } else if (nextParam instanceof String) { - String nextStringParam = (String) nextParam; - try { - String[] paramSplit = nextStringParam.split(":"); - String key = paramSplit[0]; - String value = paramSplit[1]; - theQuery = theQuery.replaceAll(":" + key, "\"" + value + "\""); - } catch(Exception e) { - log.warn("Unable to apply parameter to filter", e); - } - } - } - } - return theQuery; } } diff --git a/src/main/java/com/percero/agents/sync/metadata/SqlQuery.java b/src/main/java/com/percero/agents/sync/metadata/SqlQuery.java index 25ee7a4..f176a76 100644 --- a/src/main/java/com/percero/agents/sync/metadata/SqlQuery.java +++ b/src/main/java/com/percero/agents/sync/metadata/SqlQuery.java @@ -1,10 +1,6 @@ package com.percero.agents.sync.metadata; import org.apache.log4j.Logger; -import org.hibernate.Query; -import org.hibernate.engine.query.ParameterMetadata; -import org.hibernate.impl.SessionFactoryImpl; -import org.hibernate.impl.SessionImpl; public class SqlQuery extends MappedQuery { @@ -18,29 +14,81 @@ public SqlQuery(String query){ public SqlQuery(){ super(); } - - @Override - protected ParameterMetadata fetchParameterMetadataFromQuery(Query theQuery, SessionImpl s) { - ParameterMetadata parameterMetadata = null; - - try { - // TODO: This needs to be NativeSQL specific -// parameterMetadata = ((SessionFactoryImpl)s.getSessionFactory()).getQueryPlanCache().getNativeSQLQueryPlan(theQuery.getQueryString(), false, s.getEnabledFilters()).getParameterMetadata(); - parameterMetadata = ((SessionFactoryImpl)s.getSessionFactory()).getQueryPlanCache().getHQLQueryPlan(theQuery.getQueryString(), false, s.getEnabledFilters()).getParameterMetadata(); - } catch(Exception e) { - log.warn("Unable to get ParameterMetaData from Query:\n" + theQuery.getQueryString(), e); - } - - return parameterMetadata; - } +// ParameterMetadata parameterMetadata = null; + +// public Query createQuery(Object theObject, String userId, Object[] params, +// SessionImpl s) throws Exception { +// String queryString = getQuery(); +// queryString = setQueryParameters(queryString, theObject, userId, params); +// queryString = setParameterMetadata(queryString, theObject, userId, params, s); +// Query theQuery = s.createQuery(queryString); +// +// return theQuery; +// } - @Override - public Query createQuery(Object theObject, String userId, Object[] params, - SessionImpl s) throws Exception { - Query theQuery = s.createSQLQuery(getQuery()); - setQueryParameters(theQuery, theObject, userId, params, s); - - return theQuery; - } +// private String setParameterMetadata(String theQuery, Object theObject, String userId, Object[] params, SessionImpl s) { +// // Get Parameter MetaData. +// if (params != null && params.length > 0) { +// if (parameterMetadata == null) { +// try { +// NativeSQLQuerySpecification querySpec = null; +// parameterMetadata = ((SessionFactoryImpl)s.getSessionFactory()).getQueryPlanCache().getNativeSQLQueryPlan(querySpec).getParameterMetadata(); +// } catch(Exception e) { +// log.warn("Unable to get ParameterMetaData from Query:\n" + theQuery, e); +// } +// } +// +// for(Object nextParam : params) { +// if (nextParam instanceof Map) { +// Map nextMapParam = (Map) nextParam; +// Iterator itr = nextMapParam.entrySet().iterator(); +// while(itr.hasNext()) { +// Boolean paramSet = false; +// try { +// Map.Entry pairs = (Map.Entry) itr.next(); +// Object key = pairs.getKey(); +// Object value = pairs.getValue(); +// +// if (key instanceof String) { +// String strKey = (String) key; +// if (parameterMetadata != null) { +// NamedParameterDescriptor npd = parameterMetadata.getNamedParameterDescriptor(strKey); +// if (npd != null) { +// Type expectedType = npd.getExpectedType(); +// +// if (expectedType instanceof TimestampType) { +// Date dateValue = new Date((Long)value); +// theQuery = theQuery.replaceAll(":" + strKey, "'" + dateValue + "'"); +// } else { +// theQuery = theQuery.replaceAll(":" + (String) key, "\"" + value + "\""); +// } +// paramSet = true; +// } +// } +// +// // Last ditch effort to set this parameter. +// if (!paramSet) +// theQuery = theQuery.replaceAll(":" + (String) key, "\"" + value + "\""); +// } +// } catch(Exception e) { +// log.warn("Unable to apply parameter to filter", e); +// } +// } +// } else if (nextParam instanceof String) { +// String nextStringParam = (String) nextParam; +// try { +// String[] paramSplit = nextStringParam.split(":"); +// String key = paramSplit[0]; +// String value = paramSplit[1]; +// theQuery = theQuery.replaceAll(":" + key, "\"" + value + "\""); +// } catch(Exception e) { +// log.warn("Unable to apply parameter to filter", e); +// } +// } +// } +// } +// +// return theQuery; +// } } diff --git a/src/main/java/com/percero/agents/sync/services/AccessorService.java b/src/main/java/com/percero/agents/sync/services/AccessorService.java index 0f8a3df..80c94ac 100644 --- a/src/main/java/com/percero/agents/sync/services/AccessorService.java +++ b/src/main/java/com/percero/agents/sync/services/AccessorService.java @@ -121,7 +121,7 @@ public Accessor getReadAccessor(String userId, Class theClass, String classId, I if (hasReadAccess) { if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, theObject, userId); + mappedClass.getReadQuery().setQueryParameters(readFilter.getQueryString(), theObject, userId); List readFilterResult = readFilter.list(); if (readFilterResult == null || readFilterResult.size() == 0) hasReadAccess = false; @@ -159,7 +159,7 @@ public Map getReadAccessors(List userIds, Class theCla if (hasReadAccess) { if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, theObject, userId); + mappedClass.getReadQuery().setQueryParameters(readFilter.getQueryString(), theObject, userId); List readFilterResult = readFilter.list(); if (readFilterResult == null || readFilterResult.size() == 0) hasReadAccess = false; @@ -214,7 +214,7 @@ public Accessor getUpdateAccessor(String userId, Class theClass, String classId, if (mappedClass != null) { if (mappedClass.getUpdateQuery() != null && StringUtils.hasText(mappedClass.getUpdateQuery().getQuery())){ Query updateFilter = s.createQuery(mappedClass.getUpdateQuery().getQuery()); - mappedClass.getUpdateQuery().setQueryParameters(updateFilter, theObject, userId); + mappedClass.getUpdateQuery().setQueryParameters(updateFilter.getQueryString(), theObject, userId); List updateFilterResult = updateFilter.list(); if (updateFilterResult == null || updateFilterResult.size() == 0) hasUpdateAccess = false; @@ -269,7 +269,7 @@ public Accessor getCreateAccessor(String userId, Class theClass, String classId, if (mappedClass != null) { if (mappedClass.getCreateQuery() != null && StringUtils.hasText(mappedClass.getCreateQuery().getQuery())){ Query createFilter = s.createQuery(mappedClass.getCreateQuery().getQuery()); - mappedClass.getCreateQuery().setQueryParameters(createFilter, theObject, userId); + mappedClass.getCreateQuery().setQueryParameters(createFilter.getQueryString(), theObject, userId); List createFilterResult = createFilter.list(); if (createFilterResult == null || createFilterResult.size() == 0) hasCreateAccess = false; @@ -324,7 +324,7 @@ public Accessor getDeleteAccessor(String userId, Class theClass, String classId, if (mappedClass != null) { if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); - mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, theObject, userId); + mappedClass.getDeleteQuery().setQueryParameters(deleteFilter.getQueryString(), theObject, userId); List deleteFilterResult = deleteFilter.list(); if (deleteFilterResult == null || deleteFilterResult.size() == 0) hasDeleteAccess = false; diff --git a/src/main/java/com/percero/agents/sync/services/DAODataProvider.java b/src/main/java/com/percero/agents/sync/services/DAODataProvider.java index 249d3ef..d5ad6f3 100644 --- a/src/main/java/com/percero/agents/sync/services/DAODataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/DAODataProvider.java @@ -4,7 +4,6 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -24,36 +23,27 @@ import org.codehaus.jackson.map.ObjectMapper; import org.hibernate.PropertyValueException; import org.hibernate.Query; -import org.hibernate.QueryException; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.impl.SessionImpl; import org.hibernate.type.Type; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import com.percero.agents.sync.access.RedisKeyUtils; +import com.percero.agents.sync.dao.DAORegistry; import com.percero.agents.sync.dao.IDataAccessObject; import com.percero.agents.sync.datastore.ICacheDataStore; import com.percero.agents.sync.exceptions.SyncDataException; import com.percero.agents.sync.exceptions.SyncException; -import com.percero.agents.sync.hibernate.SyncHibernateUtils; import com.percero.agents.sync.metadata.IMappedClassManager; -import com.percero.agents.sync.metadata.JpqlQuery; import com.percero.agents.sync.metadata.MappedClass; import com.percero.agents.sync.metadata.MappedClassManagerFactory; import com.percero.agents.sync.metadata.MappedField; import com.percero.agents.sync.metadata.MappedFieldList; import com.percero.agents.sync.metadata.MappedFieldPerceroObject; -import com.percero.agents.sync.metadata.MappedFieldString; -import com.percero.agents.sync.metadata.SqlQuery; import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.ClassIDPair; import com.percero.agents.sync.vo.ClassIDPairs; import com.percero.agents.sync.vo.IJsonObject; -import com.percero.framework.metadata.IMappedQuery; import com.percero.framework.vo.IPerceroObject; import com.percero.framework.vo.PerceroList; @@ -64,13 +54,28 @@ public class DAODataProvider implements IDataProvider { private static final Logger log = Logger.getLogger(DAODataProvider.class); + private static DAODataProvider instance = null; + + public static DAODataProvider getInstance() { +// if (instance == null) { +// instance = new DAODataProvider(); +// instance.initialize(); +// } + return instance; + } + + public DAODataProvider() { + instance = this; + initialize(); + } + public void initialize() { // Do nothing. } public String getName() { - return "syncAgent"; + return "daoDataProvider"; } @Autowired @@ -79,12 +84,6 @@ public void setDataProviderManager(IDataProviderManager value) { dataProviderManager = value; } - @Autowired - DAORegistry daoRegistry; - public void setDaoRegistry(DAORegistry value) { - daoRegistry = value; - } - @Autowired ICacheDataStore cacheDataStore; @@ -96,109 +95,57 @@ public void setDaoRegistry(DAORegistry value) { - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "unchecked" }) // TODO: @Transactional(readOnly=true) public PerceroList getAllByName(String className, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception { - IDataAccessObject dao = daoRegistry.getDataAccessObject(className); - return PerceroList result = dao.getAll(pageNumber, pageSize, returnTotal, userId); - } - - @SuppressWarnings({ "rawtypes" }) - // TODO: @Transactional(readOnly=true) - public Integer countAllByName(String aClassName, String userId) throws Exception { - Session s = appSessionFactory.openSession(); - try { - Query countQuery = null; - Class theClass = MappedClass.forName(aClassName); - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); - boolean isValidReadQuery = false; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - isValidReadQuery = true; - } - } - - if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ - if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ - throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); - } - - String selectQueryString = mappedClass.getReadAllQuery().getQuery(); - - String countQueryString = "select count(*) from ("+selectQueryString+") as U"; - - countQuery = s.createSQLQuery(countQueryString); - countQuery.setParameter("userId", userId); - } - else if (theClass != null) { - String countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; - - // If the Read Query/Filter uses the ID, then we need to check against each ID here. - if (isValidReadQuery) { - String queryFilterString = mappedClass.getReadQuery().getQuery(); - if (mappedClass.getReadQuery().getUseId()) { - // Need to replace :id with - queryFilterString = queryFilterString.replaceAll(":id", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":Id", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":iD", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":ID", "getAllResult.ID"); - } - String countQueryFilterString = queryFilterString; - countQueryFilterString = countQueryString + " WHERE (" + countQueryFilterString + ") > 0"; - - countQuery = s.createQuery(countQueryFilterString); - mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); - } - else { - countQueryString += " ORDER BY ID"; - countQuery = s.createQuery(countQueryString); + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(className); + PerceroList results = dao.getAll(pageNumber, pageSize, returnTotal, userId, false); + + if (results != null && !results.isEmpty()) { + Iterator itrResults = results.iterator(); + while (itrResults.hasNext()) { + IPerceroObject nextResult = itrResults.next(); + try { + populateToManyRelationships(nextResult, true, null); + populateToOneRelationships(nextResult, true, null); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + throw new SyncDataException(e); + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new SyncDataException(e); + } catch (InvocationTargetException e) { + e.printStackTrace(); + throw new SyncDataException(e); } } - - if (countQuery != null) { -// log.debug(countQuery.toString()); - Integer result = ((Number)countQuery.uniqueResult()).intValue(); - return result; - } - else { - return null; - } - - } catch (Exception e) { - log.error("Unable to countAllByName", e); - } finally { - s.close(); } - return 0; + putObjectsInRedisCache(results); + + // Now clean the objects for the user. + List cleanedObjects = cleanObject(results, userId); + results.clear(); + results.addAll(cleanedObjects); + return results; } - public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String userId) { - Session s = appSessionFactory.openSession(); - try { - if (mappedClass != null) { - for(IMappedQuery nextQuery : mappedClass.queries) - { - if (queryName.equalsIgnoreCase(nextQuery.getQueryName())) - { - Query readFilter = s.createQuery(nextQuery.getQuery()); - nextQuery.setQueryParameters(readFilter, queryArguments, userId, queryArguments, (SessionImpl)s); - return processQueryResults(mappedClass.className + "_" + queryName, readFilter, readFilter.list()); - } - } - } - } catch (Exception e) { - log.error("Unable to runQuery", e); - } finally { - if (s != null && s.isOpen()) - s.close(); - } + @SuppressWarnings({ "unchecked" }) + // TODO: @Transactional(readOnly=true) + public Integer countAllByName(String className, String userId) throws Exception { + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(className); + Integer result = dao.countAll(userId); + return result; + } - return null; + @SuppressWarnings("unchecked") + public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String userId) throws SyncException { + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(mappedClass.className); + List result = dao.runQuery(queryName, queryArguments, userId); + return result; } + // TODO: This method has not been tested and is most likely broken. @SuppressWarnings({ "rawtypes", "unchecked" }) protected static List processQueryResults(String resultClassName, Query updateFilter, List updateFilterResult) throws Exception { String[] returnAliases = updateFilter.getReturnAliases(); @@ -276,164 +223,83 @@ protected static List processQueryResults(String resultClassName, Query return results; } - //@SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings("unchecked") public IPerceroObject findById(ClassIDPair classIdPair, String userId) { - boolean hasReadQuery = false; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - hasReadQuery = true; - } - } - Session s = null; try { - boolean hasAccess = true; - IPerceroObject result = systemGetById(classIdPair); - - if (result != null) { - if (hasReadQuery) { - if (s == null) - s = appSessionFactory.openSession(); - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - - if (hasAccess) { - if (s == null) - s = appSessionFactory.openSession(); -// ((BaseDataObject)result).setIsClean(false); - result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s, userId); - return result; + IPerceroObject result = retrieveFromRedisCache(classIdPair); + + if (result == null) { + + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(classIdPair.getClassName()); + // Retrieve results BEFORE applying access rules so that our cached value represents the full object. + result = dao.retrieveObject(classIdPair, null, false); + populateToManyRelationships(result, true, null); + populateToOneRelationships(result, true, null); + + // Now put the object in the cache. + if (result != null) { + putObjectInRedisCache(result); } else { - return null; + // Not necessarily a problem but could be helpful when debugging. + log.debug("Unable to retrieve object from database: " + classIdPair.toJson()); } } else { - return null; + // (Re)Set the expiration. + setObjectExpiration(result); } - } catch (Exception e) { - log.error("Unable to findById", e); - } finally { - if (s != null && s.isOpen()) - s.close(); + + result = cleanObject(result, userId); + + return result; + } catch(Exception e) { + log.error("Unable to findById: "+classIdPair.toJson(), e); } + return null; } - @SuppressWarnings({ "rawtypes", "unchecked" }) - public IPerceroObject systemGetById(ClassIDPair classIdPair) { - Session s = null; - try { - Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); - - if (theClass != null) { - IPerceroObject result = retrieveFromRedisCache(classIdPair); - String key = null; - - if (result == null) { - result = readObjectFromDatabase(classIdPair, false); - populateToManyRelationships(result, true, null); - populateToOneRelationships(result, true, null); - /** - * CRB: Going direct to database instead. - s = appSessionFactory.openSession(); - result = (IPerceroObject) s.get(theClass, classIdPair.getID()); - */ - - // Now put the object in the cache. - if (result != null) { - key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); -// result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); - if (cacheTimeout > 0) - cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); - } - else { - // Not necessarily a problem but could be helpful when debugging. - log.debug("Unable to retrieve object from database: " + classIdPair.toJson()); - } - } - else { - key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); - } - - // (Re)Set the expiration. - if (cacheTimeout > 0 && key != null) { - cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); - } + private void putObjectInRedisCache(IPerceroObject perceroObject) { + // Now put the object in the cache. + if (cacheTimeout > 0 && perceroObject != null) { + String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + setObjectExpiration(key); + } + } + + private void putObjectsInRedisCache(List results) { + if (cacheTimeout > 0) { + Map mapJsonObjectStrings = new HashMap(results.size()); + Iterator itrDatabaseObjects = results.iterator(); + while (itrDatabaseObjects.hasNext()) { + IPerceroObject nextDatabaseObject = itrDatabaseObjects.next(); + String nextCacheKey = RedisKeyUtils.classIdPair(nextDatabaseObject.getClass().getCanonicalName(), nextDatabaseObject.getID()); - return result; - } else { - return null; + mapJsonObjectStrings.put(nextCacheKey, ((BaseDataObject)nextDatabaseObject).toJson()); } - } catch (Exception e) { - log.error("Unable to systemGetById: "+classIdPair.toJson(), e); - } finally { - if (s != null && s.isOpen()) - s.close(); + + // Store the objects in redis. + cacheDataStore.setValues(mapJsonObjectStrings); + // (Re)Set the expiration. + cacheDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); + } + } + + private void setObjectExpiration(IPerceroObject perceroObject) { + setObjectExpiration(RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID())); + } + + private void setObjectExpiration(String key) { + // (Re)Set the expiration. + if (cacheTimeout > 0 && key != null) { + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); } - return null; } -// @SuppressWarnings({ "rawtypes" }) -// public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, Class theClass, Session s) { -// Boolean sessionAlreadyOpen = false; -// try { -// if (theClass != null) { -// IPerceroObject result = retrieveFromRedisCache(classIdPair); -// String key = null; -// -// if (result == null) { -// if (s == null || !s.isOpen()) { -// s = appSessionFactory.openSession(); -// } -// else { -// sessionAlreadyOpen = true; -// } -// result = (IPerceroObject) s.get(theClass, classIdPair.getID()); -// -// // Now put the object in the cache. -// if (result != null) { -// key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); -// result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); -// if (cacheTimeout > 0) -// redisDataStore.setValue(key, ((BaseDataObject)result).toJson()); -// } -// else { -// log.warn("Unable to retrieve object from database: " + classIdPair.toString()); -// } -// } -// else { -// key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); -// } -// -// // (Re)Set the expiration. -// if (cacheTimeout > 0 && key != null) { -// redisDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); -// } -// -// return result; -// } else { -// return null; -// } -// } catch (Exception e) { -// log.error("Unable to systemGetById: "+classIdPair.toJson(), e); -// } finally { -// // Only close the session if it wasn't already open. -// if (!sessionAlreadyOpen) { -// if (s != null && s.isOpen()) { -// s.close(); -// } -// } -// } -// return null; -// } @SuppressWarnings({ "rawtypes", "unchecked" }) private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Exception { @@ -468,7 +334,7 @@ private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Ex } } } - } + } return result; } @@ -542,664 +408,110 @@ private Map retrieveFromRedisCache(ClassIDPairs classIdP return result; } - @SuppressWarnings({ "rawtypes" }) + @SuppressWarnings({ }) public Boolean getReadAccess(ClassIDPair classIdPair, String userId) { - Session s = appSessionFactory.openSession(); - try { - Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); - - if (theClass != null) { - IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); - - boolean hasAccess = (parent != null); - - if (hasAccess) { - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, parent, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - } - } - - return hasAccess; - } - } catch (Exception e) { - log.error("Unable to getReadAccess", e); - } finally { - s.close(); - } - return false; + IDataAccessObject dao = DAORegistry.getInstance().getDataAccessObject(classIdPair.getClassName()); + return dao.hasReadAccess(classIdPair, userId); } - @SuppressWarnings({ "rawtypes" }) + @SuppressWarnings({ }) public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { - Session s = appSessionFactory.openSession(); - try { - Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); - - if (theClass != null) { - IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); - - if (parent == null) - return true; - - boolean hasAccess = true; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); - if (mappedClass != null) { - if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ - Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); - mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, parent, userId); - Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); - if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) - hasAccess = false; - } - } - - return hasAccess; - } - } catch (Exception e) { - log.error("Unable to getDeleteAccess", e); - } finally { - s.close(); - } - return false; + IDataAccessObject dao = DAORegistry.getInstance().getDataAccessObject(classIdPair.getClassName()); + return dao.hasDeleteAccess(classIdPair, userId); } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ }) public List findByIds(ClassIDPairs classIdPairs, String userId) { - List result = null; + IDataAccessObject dao = DAORegistry.getInstance().getDataAccessObject(classIdPairs.getClassName()); + List results = new ArrayList(); - boolean hasAccess = true; - Class theClass = null; try { - theClass = MappedClass.forName(classIdPairs.getClassName()); - } catch (ClassNotFoundException e2) { - log.error("Unable to get Class from class name " + classIdPairs.getClassName(), e2); - return result; - } - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPairs.getClassName()); - boolean isValidReadQuery = false; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - isValidReadQuery = true; - } - - } - - if (hasAccess) { - if (theClass != null) { - Set idsSet = new HashSet(classIdPairs.getIds().size()); - idsSet.addAll(classIdPairs.getIds()); - - try { - // Attempt to get as many from the cache as possible... - Map cachedObjects = retrieveFromRedisCache(classIdPairs, true); - - if (!cachedObjects.isEmpty()) { - result = new ArrayList(cachedObjects.size()); - List cachedResults = new ArrayList(cachedObjects.size()); - cachedResults.addAll(cachedObjects.values()); - idsSet.removeAll(cachedObjects.keySet()); - - // If there is a read query, we need to check each object through that query. - if (isValidReadQuery) { - Session s = null; - try { - // Need to clean each result for the user. - // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function - s = appSessionFactory.openSession(); - - Iterator itrCachedResults = cachedResults.iterator(); - while (itrCachedResults.hasNext()) { - IPerceroObject nextCachedResult = itrCachedResults.next(); - if (isValidReadQuery) { - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, nextCachedResult, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - - if (hasAccess) { - result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); - } - } - } catch (Exception e) { - log.error("Error cleaning object for user in findByIds", e); - } finally { - if (s != null && s.isOpen()) { - s.close(); - } - } - } - else { - // This class has relationship objects that need to be cleaned. - if (!mappedClass.getReadAccessRightsFieldReferences().isEmpty()) { - Session s = null; - try { - // Need to clean each result for the user. - // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function - // TODO: Maybe only clean relationships that are in mappedClass.readAccessRightsFieldReferences? - s = appSessionFactory.openSession(); - - Iterator itrCachedResults = cachedResults.iterator(); - while (itrCachedResults.hasNext()) { - IPerceroObject nextCachedResult = itrCachedResults.next(); - result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); - } - } catch (Exception e) { - log.error("Error cleaning object for user in findByIds", e); - } finally { - if (s != null && s.isOpen()) { - s.close(); - } - } - } - else { - // This class has NO read access query AND has NO relationships that require cleaning, - // since this object is completely retrieved from redis, we can send as-is. - // Though this may seem rare, this is probably a very common path. - result.addAll(cachedResults); - } - } - } - } catch (Exception e1) { - // We errored out here, but we can still try and retrieve from the database. - log.error("Error retrieving objects from redis cache, attempting to retrieve from database", e1); - } + // Copy the ClassIDPairs to find object since we remove any of the + // ID's from the list that we find in the cache. + ClassIDPairs classIdPairsCopy = new ClassIDPairs(); + classIdPairsCopy.setClassName(classIdPairs.getClassName()); + List idsToFind = new ArrayList(classIdPairs.getIds().size()); + idsToFind.addAll(classIdPairs.getIds()); + classIdPairsCopy.setIds(idsToFind); + + Map cachedResults = retrieveFromRedisCache(classIdPairs, true); + if (cachedResults != null &&!cachedResults.isEmpty()) { + // Add the cached results - // Now get the rest from the database. - if (!idsSet.isEmpty()) { - - - /** - * CRB: Going direct to database instead of Hibernate - String queryString = "SELECT findByIdsResult FROM " + classIdPairs.getClassName() + " findByIdsResult WHERE findByIdsResult.ID IN (:idsSet)"; - */ - - // Open the database session. - Session s = null; - try { - s = appSessionFactory.openSession(); - /** - * CRB: Going direct to database instead of Hibernate - Query query = null; - - // If the Read Query/Filter uses the ID, then we need to check against each ID here. - if (isValidReadQuery) { - String queryFilterString = mappedClass.getReadQuery().getQuery(); - if (mappedClass.getReadQuery().getUseId()) { - // Need to replace :id with - queryFilterString = queryFilterString.replaceAll(":id", "findByIdsResult.ID"); - queryFilterString = queryFilterString.replaceAll(":Id", "findByIdsResult.ID"); - queryFilterString = queryFilterString.replaceAll(":iD", "findByIdsResult.ID"); - queryFilterString = queryFilterString.replaceAll(":ID", "findByIdsResult.ID"); - } - queryFilterString = queryString + " AND (" + queryFilterString + ") > 0"; - - query = s.createQuery(queryFilterString); - mappedClass.getReadQuery().setQueryParameters(query, null, userId); - } - else { - query = s.createQuery(queryString); - } - - query.setParameterList("idsSet", idsSet); - List queryResult = query.list(); - */ - List queryResult = readObjectsFromDatabase(classIdPairs, userId); - - for(IPerceroObject nextResult : queryResult) { - populateToManyRelationships(nextResult, true, userId); - populateToOneRelationships(nextResult, true, userId); - } - List cleanedDatabaseObjects = queryResult; - // -// List cleanedDatabaseObjects = (List) SyncHibernateUtils.cleanObject(queryResult, s); - - // Need to put results into cache. - if (cacheTimeout > 0) { - Map mapJsonObjectStrings = new HashMap(cleanedDatabaseObjects.size()); - Iterator itrDatabaseObjects = cleanedDatabaseObjects.iterator(); - while (itrDatabaseObjects.hasNext()) { - IPerceroObject nextDatabaseObject = itrDatabaseObjects.next(); - String nextCacheKey = RedisKeyUtils.classIdPair(nextDatabaseObject.getClass().getCanonicalName(), nextDatabaseObject.getID()); - - mapJsonObjectStrings.put(nextCacheKey, ((BaseDataObject)nextDatabaseObject).toJson()); - } - - // Store the objects in redis. - cacheDataStore.setValues(mapJsonObjectStrings); - // (Re)Set the expiration. - cacheDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); - } - - // Clean the objects for the selected User. - cleanedDatabaseObjects = (List) SyncHibernateUtils.cleanObject(cleanedDatabaseObjects, s, userId); - if (result == null) { - result = cleanedDatabaseObjects; - } - else { - result.addAll(cleanedDatabaseObjects); - } - } catch (QueryException qe) { - log.error("Unable to findByIds", qe); - } catch (Exception e) { - log.error("Unable to findByIds", e); - } finally { - if (s != null && s.isOpen()) { - s.close(); - } + Iterator itrCachedResults = cachedResults.values().iterator(); + while (itrCachedResults.hasNext()) { + IPerceroObject nextCachedResult = itrCachedResults.next(); + if (nextCachedResult != null) { + idsToFind.remove(nextCachedResult.getID()); + results.add(nextCachedResult); + setObjectExpiration(nextCachedResult); } } } - } - return result; - } - - /** - * CRB: This is the same as findByExample, filtering out the first result. - @SuppressWarnings({ "rawtypes", }) - public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId) throws SyncException { - - MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(theQueryObject.getClass().getCanonicalName()); - if (mappedClass == null) { - log.warn("Missing MappedClass for " + theQueryObject.getClass().getCanonicalName()); - throw new SyncException(SyncException.MISSING_MAPPED_CLASS_ERROR, SyncException.MISSING_MAPPED_CLASS_ERROR_CODE ); - } - - Session s = appSessionFactory.openSession(); - try { - Class objectClass = theQueryObject.getClass(); - - Iterator> itr = mappedClass.uniqueConstraints.iterator(); - while(itr.hasNext()) { - Criteria criteria = null; - List nextConstraint = itr.next(); - -// if (nextConstraint instanceof MappedField) { -// MappedField nextConstraintField = (MappedField) nextConstraint; -// Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); -// if (nextConstraintFieldValue != null) { -// if (criteria == null) -// criteria = s.createCriteria(objectClass); -// Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); -// criteria.add(uniqueFieldValue); -// } -// } -// else if (nextConstraint instanceof List) { - - List listMappedFields = (List) nextConstraint; - Iterator itrMappedFields = listMappedFields.iterator(); - while(itrMappedFields.hasNext()) { - MappedField nextConstraintField = itrMappedFields.next(); - - if (nextConstraintField.isValueSetForQuery(theQueryObject)) { - - } - - Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); - if (nextConstraintFieldValue != null) { - if (criteria == null) - criteria = s.createCriteria(objectClass); - Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); - criteria.add(uniqueFieldValue); - } + List daoObjects = null; + if (classIdPairsCopy.getIds() != null && !classIdPairsCopy.getIds().isEmpty()) { + daoObjects = dao.retrieveObjects(classIdPairsCopy, userId, false); + + for(IPerceroObject nextResult : daoObjects) { + populateToManyRelationships(nextResult, true, null); + populateToOneRelationships(nextResult, true, null); } - if (criteria != null) { - criteria.setMaxResults(1); - Object result = criteria.uniqueResult(); - if (result != null) { - // Make sure user has access. - boolean hasAccess = true; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - } - - if (hasAccess) { - result = SyncHibernateUtils.cleanObject(result, s, userId); - return (IPerceroObject) result; - } - } - } + putObjectsInRedisCache(daoObjects); // Only need to put objects in cache that were not already found in cache. + results.addAll(daoObjects); } - } catch (Exception e) { - log.error("Unable to findUnique", e); - } finally { - s.close(); - } - return null; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public IPerceroObject findUnique_OLD(IPerceroObject theQueryObject, String userId) { - Session s = appSessionFactory.openSession(); - try { - Class objectClass = theQueryObject.getClass(); + // Now clean the objects for the user. + results = cleanObject(results, userId); - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(objectClass.getName()); - if (mappedClass != null) { - Iterator itr = mappedClass.uniqueConstraints.iterator(); - while(itr.hasNext()) { - Criteria criteria = null; - Object nextConstraint = itr.next(); - if (nextConstraint instanceof MappedField) { - MappedField nextConstraintField = (MappedField) nextConstraint; - Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); - if (nextConstraintFieldValue != null) { - if (criteria == null) - criteria = s.createCriteria(objectClass); - Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); - criteria.add(uniqueFieldValue); - } - } - else if (nextConstraint instanceof List) { - List listMappedFields = (List) nextConstraint; - Iterator itrMappedFields = listMappedFields.iterator(); - while(itrMappedFields.hasNext()) { - MappedField nextConstraintField = itrMappedFields.next(); - Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); - if (nextConstraintFieldValue != null) { - if (criteria == null) - criteria = s.createCriteria(objectClass); - Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); - criteria.add(uniqueFieldValue); - } - } - } - - if (criteria != null) { - criteria.setMaxResults(1); - Object result = criteria.uniqueResult(); - if (result != null) { - // Make sure user has access. - boolean hasAccess = true; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - } - - if (hasAccess) { - result = SyncHibernateUtils.cleanObject(result, s, userId); - return (IPerceroObject) result; - } - } - } - } - } - } catch (Exception e) { - log.error("Unable to findUnique", e); - } finally { - s.close(); - } - - return null; - } - */ - - // TODO: Add permissions check. - @SuppressWarnings("unchecked") - public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId) throws SyncException { - List result = systemFindByExample(theQueryObject, excludeProperties); - if (result != null) { - // Make sure user has access. - boolean hasAccess = true; - - MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(theQueryObject.getClass().getCanonicalName()); - Session s = appSessionFactory.openSession(); - try { - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ - Query readFilter = mappedClass.getReadQuery().createQuery(result, userId, null, (SessionImpl)s); -// Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); -// mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) { - hasAccess = false; - } - } - } - - if (hasAccess) { - result = (List) SyncHibernateUtils.cleanObject(result, s, userId); - } - } catch (Exception e) { - log.error("Unable to findByExample", e); - throw new SyncDataException(e); - } finally { - s.close(); - } + } catch(Exception e) { + log.error(e); + e.printStackTrace(); } - - return result; -// Session s = appSessionFactory.openSession(); -// try { -// Criteria criteria = s.createCriteria(theQueryObject.getClass()); -// AssociationExample example = AssociationExample.create(theQueryObject); -// BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); -// example.setPropertySelector(propertySelector); -// criteria.add(example); -// -// List result = criteria.list(); -// result = (List) SyncHibernateUtils.cleanObject(result, s, userId); -// -// return (List) result; -// } catch (Exception e) { -// log.error("Unable to findByExample", e); -// } finally { -// s.close(); -// } -// -// return null; + return results; } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public List systemFindByExample(IPerceroObject theQueryObject, List excludeProperties) throws SyncException { - // TODO: Use StringBuilder or something more efficient here. - List result = new ArrayList(); - - MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(theQueryObject.getClass().getCanonicalName()); - if (mappedClass == null) { - log.warn("Missing MappedClass for " + theQueryObject.getClass().getCanonicalName()); - throw new SyncException(SyncException.MISSING_MAPPED_CLASS_ERROR, SyncException.MISSING_MAPPED_CLASS_ERROR_CODE ); - } - - String selectQueryString = "SELECT "; - String whereString = "WHERE "; - List wherePropertyFields = new ArrayList(); - List whereToOneFields = new ArrayList(); - -// if (excludeProperties == null) { -// excludeProperties = new ArrayList(1); -// } -// if (!excludeProperties.contains(mappedClass.idMappedField)) { -// excludeProperties.add(mappedClass.idMappedField.); -// } - - int selectCounter = 0; - int whereCounter = 0; - - // Iterate over PropertyFields. These are simple fields with their value being stored here. - for(MappedField nextMappedField : mappedClass.propertyFields) { - if (selectCounter > 0) { - selectQueryString += ", "; - } - - selectQueryString += "P." + nextMappedField.getColumnName(); - selectCounter++; - - // Now check the QueryObject to see if this field is a filter. - try { - if (nextMappedField != mappedClass.idMappedField && nextMappedField.isValueSetForQuery(theQueryObject)) { - if (whereCounter > 0) { - whereString += " AND "; - } - if (nextMappedField instanceof MappedFieldString) { - whereString += "P." + nextMappedField.getColumnName() + " LIKE(:" + nextMappedField.getColumnName() + ")"; - } - else { - whereString += "P." + nextMappedField.getColumnName() + "=:" + nextMappedField.getColumnName(); - } - wherePropertyFields.add(nextMappedField); - whereCounter++; - } - } catch (IllegalArgumentException e) { - // Don't necessarily care about this here. - } catch (IllegalAccessException e) { - // Don't necessarily care about this here. - } catch (InvocationTargetException e) { - // Don't necessarily care about this here. - } - } + @SuppressWarnings("unchecked") + public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId, Boolean shellOnly) throws SyncException { + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(theQueryObject.getClass().getCanonicalName()); + List results = dao.findByExample(theQueryObject, excludeProperties, userId, shellOnly); - // Iterate over ToOneFields, meaning fields where the ID of the relationship is stored on this side of the relationship. - for(MappedFieldPerceroObject nextMappedField : mappedClass.toOneFields) { - - // If this mapped field is the source, then we include it in our query. - if (nextMappedField.isSourceEntity()) { - if (selectCounter > 0) { - selectQueryString += ", "; - } - - selectQueryString += "P." + nextMappedField.getJoinColumnName(); - selectCounter++; - - // Now check the QueryObject to see if this field is a filter. + if (results != null && !results.isEmpty()) { + Iterator itrResults = results.iterator(); + while (itrResults.hasNext()) { + IPerceroObject nextResult = itrResults.next(); try { - if (nextMappedField != mappedClass.idMappedField && nextMappedField.isValueSetForQuery(theQueryObject)) { - if (whereCounter > 0) { - whereString += " AND "; - } - whereString += "P." + nextMappedField.getJoinColumnName() + "=:" + nextMappedField.getJoinColumnName(); - whereToOneFields.add(nextMappedField); - whereCounter++; - } + populateToManyRelationships(nextResult, true, null); + populateToOneRelationships(nextResult, true, null); } catch (IllegalArgumentException e) { - // Don't necessarily care about this here. + e.printStackTrace(); + throw new SyncDataException(e); } catch (IllegalAccessException e) { - // Don't necessarily care about this here. + e.printStackTrace(); + throw new SyncDataException(e); } catch (InvocationTargetException e) { - // Don't necessarily care about this here. + e.printStackTrace(); + throw new SyncDataException(e); } } - else { - System.out.println("No Join Column"); - } } - // If there are no Query Fields set, then we simply return an empty list. - if ( (selectCounter + whereCounter) == 0) { - return result; - } - - String fullQueryString = selectQueryString + " FROM " + (StringUtils.hasText(mappedClass.tableSchema) ? mappedClass.tableSchema + "." : "") + mappedClass.tableName + " P " + whereString; - - Session s = appSessionFactory.openSession(); - try { - Query query = s.createSQLQuery(fullQueryString); - - for(MappedField nextMappedField : wherePropertyFields) { - // We know this field has a valid value here. - if (nextMappedField instanceof MappedFieldString) { - query.setParameter(nextMappedField.getColumnName(), "%" + nextMappedField.getValue(theQueryObject) + "%"); - } - else { - query.setParameter(nextMappedField.getColumnName(), nextMappedField.getValue(theQueryObject)); - } - } - for(MappedField nextMappedField : whereToOneFields) { - // Because we know this field has a value set, we know it is an IPerceroObject with valid ID. - query.setParameter(nextMappedField.getJoinColumnName(), ((IPerceroObject) nextMappedField.getValue(theQueryObject)).getID() ); - } - - List queryResult = query.list(); - - Iterator itrQueryResults = queryResult.iterator(); - while (itrQueryResults.hasNext()) { - - IPerceroObject nextPerceroObject = (IPerceroObject) mappedClass.clazz.newInstance(); - - Object[] nextResult = (Object[]) itrQueryResults.next(); - - int j = 0; - for(MappedField nextMappedField : mappedClass.propertyFields) { - Object nextValue = nextResult[j]; - nextMappedField.getSetter().invoke(nextPerceroObject, nextValue); - j++; - } - for(MappedFieldPerceroObject nextMappedField : mappedClass.toOneFields) { - if (nextMappedField.isSourceEntity()) { - Object nextValue = nextResult[j]; - - IPerceroObject nextToOnePerceroObject = (IPerceroObject) nextMappedField.getField().getType().newInstance(); - nextToOnePerceroObject.setID( (String) nextValue ); - - if (!nextMappedField.getUseLazyLoading()) { - IDataProvider dataProvider = nextMappedField.getMappedClass().getDataProvider(); - nextToOnePerceroObject = dataProvider.systemGetById(BaseDataObject.toClassIdPair(nextToOnePerceroObject)); - } - - nextMappedField.getSetter().invoke(nextPerceroObject, nextToOnePerceroObject); - } - } - - nextPerceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(nextPerceroObject, s); - addObjectToCache(nextPerceroObject); - - result.add(nextPerceroObject); - } - } catch(Exception e) { - log.error("Unable to systemFindByExample", e); - // TODO: Throw a SyncException here. - } finally { - s.close(); - } + putObjectsInRedisCache(results); - // Now clean the results. - result = (List) SyncHibernateUtils.cleanObject(result, s, null); + // Now clean the objects for the user. + results = cleanObject(results, userId); - return result; - } - - @SuppressWarnings("unchecked") - public List searchByExample(IPerceroObject theQueryObject, - List excludeProperties, String userId) throws SyncException { - return findByExample(theQueryObject, excludeProperties, userId); + return results; } @SuppressWarnings({ "unchecked", "rawtypes" }) - public IPerceroObject systemCreateObject(IPerceroObject perceroObject) - throws SyncException { -// Session s = appSessionFactory.openSession(); + public T createObject(T perceroObject, String userId) throws SyncException { try { + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(perceroObject.getClass().getCanonicalName()); // Make sure object has an ID. IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); @@ -1207,27 +519,28 @@ public IPerceroObject systemCreateObject(IPerceroObject perceroObject) perceroObject.setID(UUID.randomUUID().toString()); else { // Check to see if item already exists. - IPerceroObject existingObject = readObjectFromDatabase(BaseDataObject.toClassIdPair(perceroObject), false); + IPerceroObject existingObject = dao.retrieveObject(BaseDataObject.toClassIdPair(perceroObject), null, false); if (existingObject != null) { populateToManyRelationships(perceroObject, true, null); populateToOneRelationships(perceroObject, true, null); - return perceroObject; + return (T) cleanObject(perceroObject, userId); } } - insertObjectIntoDatabase(perceroObject); + perceroObject = (T) dao.createObject(perceroObject, userId); + if (perceroObject == null) { + return perceroObject; + } populateToManyRelationships(perceroObject, true, null); populateToOneRelationships(perceroObject, true, null); - + // Now update the cache. // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... if (cacheTimeout > 0) { String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); - if (cacheTimeout > 0) { - cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); - cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); - } + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); Set keysToDelete = new HashSet(); MappedClass nextMappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); @@ -1281,7 +594,7 @@ else if (fieldObject instanceof Collection) { } } - return perceroObject; + return (T) cleanObject(perceroObject, userId); } catch(PropertyValueException pve) { log.error("Error creating object", pve); @@ -1298,215 +611,128 @@ else if (fieldObject instanceof Collection) { } } -// private void deepCleanObject(IPerceroObject perceroObject, MappedClass mappedClass, Session s, String userId) { -// if (!(perceroObject instanceof IRootObject)) { -// for(MappedField nextMappedField : mappedClass.externalizableFields) { -// try { -// if (nextMappedField instanceof MappedFieldPerceroObject) { -// Object fieldValue = nextMappedField.getValue(perceroObject); -// if (fieldValue != null) { -// fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); -// nextMappedField.getSetter().invoke(perceroObject, fieldValue); -// } -// } -// else if (nextMappedField instanceof MappedFieldList) { -// Object fieldValue = nextMappedField.getValue(perceroObject); -// if (fieldValue != null) { -// fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); -// nextMappedField.getSetter().invoke(perceroObject, fieldValue); -// } -// } -// else if (nextMappedField instanceof MappedFieldMap) { -// Object fieldValue = nextMappedField.getValue(perceroObject); -// if (fieldValue != null) { -// fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); -// nextMappedField.getSetter().invoke(perceroObject, fieldValue); -// } -// } -// } catch(Exception e) { -// log.error("Error in postCreateObject " + mappedClass.className + "." + nextMappedField.getField().getName(), e); -// } -// } -// } -// } - - public IPerceroObject createObject(IPerceroObject perceroObject, String userId) throws SyncException { - boolean hasAccess = true; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - if (mappedClass != null) { - if (mappedClass.getCreateQuery() != null && StringUtils.hasText(mappedClass.getCreateQuery().getQuery())){ - Session s = appSessionFactory.openSession(); - try { - Query createFilter = s.createQuery(mappedClass.getCreateQuery().getQuery()); - mappedClass.getCreateQuery().setQueryParameters(createFilter, perceroObject, userId); - Number createFilterResult = (Number) createFilter.uniqueResult(); - if (createFilterResult == null || createFilterResult.intValue() <= 0) - hasAccess = false; - } catch (Exception e) { - log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); - hasAccess = false; - } finally { - s.close(); - } - } - } - - if (hasAccess) { - return systemCreateObject(perceroObject); - } else { - return null; - } - } - - //////////////////////////////////////////////////// // PUT //////////////////////////////////////////////////// - public IPerceroObject putObject(IPerceroObject perceroObject, Map> changedFields, String userId) throws SyncException { - boolean hasAccess = true; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - if (mappedClass != null) { - if (mappedClass.getUpdateQuery() != null && StringUtils.hasText(mappedClass.getUpdateQuery().getQuery())){ - Session s = appSessionFactory.openSession(); - try { - Query updateFilter = null; - if (mappedClass.getUpdateQuery() instanceof JpqlQuery) { - updateFilter = s.createQuery(mappedClass.getUpdateQuery().getQuery()); - } - else if (mappedClass.getUpdateQuery() instanceof SqlQuery) { - updateFilter = s.createSQLQuery(mappedClass.getUpdateQuery().getQuery()); - } - mappedClass.getUpdateQuery().setQueryParameters(updateFilter, perceroObject, userId); - Number updateFilterResult = (Number) updateFilter.uniqueResult(); - if (updateFilterResult == null || updateFilterResult.intValue() <= 0) - hasAccess = false; - } catch (Exception e) { - log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); - hasAccess = false; - } finally { - s.close(); - } - } - } - - if (hasAccess) { - return systemPutObject(perceroObject, changedFields); - } else { - return null; - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map> changedFields) throws SyncException { - + @SuppressWarnings("unchecked") + public T putObject(T perceroObject, Map> changedFields, String userId) throws SyncException { + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(perceroObject.getClass().getCanonicalName()); + perceroObject = (T) dao.updateObject(perceroObject, changedFields, userId); + try { - updateObjectInDatabase(perceroObject, changedFields); // If write fails, an exception will be thrown. - - if (changedFields != null && !changedFields.isEmpty()) { - // Since changedFields was set, it is possible (and likely) that perceroObject is only PARTIALLY filled out, so load the full object. - // Re-fetch the full object from the database. - perceroObject = readObjectFromDatabase(BaseDataObject.toClassIdPair(perceroObject), false); - populateToManyRelationships(perceroObject, true, null); - populateToOneRelationships(perceroObject, true, null); + populateToManyRelationships(perceroObject, true, null); + populateToOneRelationships(perceroObject, true, null); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + throw new SyncException(e); + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new SyncException(e); + } catch (InvocationTargetException e) { + e.printStackTrace(); + throw new SyncException(e); + } + // Now update the cache. + if (cacheTimeout > 0) { + // TODO: Also need to update the caches of anything object that is related to this object. + String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); + if (cacheDataStore.hasKey(key)) { + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); } - // Now update the cache. - // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... - if (cacheTimeout > 0) { - // TODO: Also need to update the caches of anything object that is related to this object. - String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); - if (cacheDataStore.hasKey(key)) { - cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + // Iterate through each changed object and reset the cache for that object. + if (changedFields != null) { + Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); + Set keysToDelete = new HashSet(); + while (itrChangedFieldKeyset.hasNext()) { + ClassIDPair thePair = itrChangedFieldKeyset.next(); + if (!thePair.comparePerceroObject(perceroObject)) { + String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); + keysToDelete.add(nextKey); + } } - // Iterate through each changed object and reset the cache for that object. - if (changedFields != null) { -// Iterator>> itrChangedFieldEntrySet = changedFields.entrySet().iterator(); -// Set keysToDelete = new HashSet(); -// while (itrChangedFieldEntrySet.hasNext()) { -// Map.Entry> nextEntry = itrChangedFieldEntrySet.next(); -// ClassIDPair thePair = nextEntry.getKey(); -// if (!thePair.comparePerceroObject(perceroObject)) { -// String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); -// keysToDelete.add(nextKey); -// } -// } - Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); - Set keysToDelete = new HashSet(); - while (itrChangedFieldKeyset.hasNext()) { - ClassIDPair thePair = itrChangedFieldKeyset.next(); - if (!thePair.comparePerceroObject(perceroObject)) { - String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); - keysToDelete.add(nextKey); - } - } - - if (!keysToDelete.isEmpty()) { - cacheDataStore.deleteKeys(keysToDelete); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } + if (!keysToDelete.isEmpty()) { + cacheDataStore.deleteKeys(keysToDelete); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); } - else { - // No changedFields? We should never get here? - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - Iterator itrToManyFields = mappedClass.toManyFields.iterator(); - while(itrToManyFields.hasNext()) { - MappedField nextMappedField = itrToManyFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); - if (cacheDataStore.hasKey(nextKey)) { - cacheDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } + } + else { + // No changedFields? We should never get here? + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + Iterator itrToManyFields = mappedClass.toManyFields.iterator(); + while(itrToManyFields.hasNext()) { + MappedField nextMappedField = itrToManyFields.next(); + Object fieldObject = null; + try { + fieldObject = nextMappedField.getGetter().invoke(perceroObject); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); - if (cacheDataStore.hasKey(nextKey)) { - cacheDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); } } } } } - Iterator itrToOneFields = mappedClass.toOneFields.iterator(); - while(itrToOneFields.hasNext()) { - MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); - if (cacheDataStore.hasKey(nextKey)) { - cacheDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } + } + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + while(itrToOneFields.hasNext()) { + MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); + Object fieldObject = null; + try { + fieldObject = nextMappedField.getGetter().invoke(perceroObject); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); - if (cacheDataStore.hasKey(nextKey)) { - cacheDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); } } } @@ -1514,74 +740,22 @@ else if (fieldObject instanceof Collection) { } } } - - return perceroObject; - } catch (Exception e) { - log.error("Error putting object", e); - - SyncDataException sde = new SyncDataException(SyncDataException.UPDATE_OBJECT_ERROR, SyncDataException.UPDATE_OBJECT_ERROR_CODE); - throw sde; } + + return (T) cleanObject(perceroObject, userId); } - //////////////////////////////////////////////////// // DELETE //////////////////////////////////////////////////// - public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws SyncException { - Session s = appSessionFactory.openSession(); - - try { - IPerceroObject perceroObject = readObjectFromDatabase(theClassIdPair, true); -// IPerceroObject perceroObject = (IPerceroObject) s.get(theClassIdPair.getClassName(), theClassIdPair.getID()); - if (perceroObject == null) { - return true; - } - - boolean hasAccess = true; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(theClassIdPair.getClassName()); - if (mappedClass != null) { - if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ - Query deleteFilter = null; - if (mappedClass.getDeleteQuery() instanceof JpqlQuery) { - deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); - } - else if (mappedClass.getDeleteQuery() instanceof SqlQuery) { - deleteFilter = s.createSQLQuery(mappedClass.getDeleteQuery().getQuery()); - } - mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, perceroObject, userId); - Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); - if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) - hasAccess = false; - } - } - - if (hasAccess) { - if (systemDeleteObject(perceroObject)) { - return true; - } - else { - return true; - } - } else { - log.warn("No access to delete object " + theClassIdPair.toString()); - return false; - } - } catch (Exception e) { - log.error("Error putting object", e); - return false; - } finally { - s.close(); - } - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Boolean systemDeleteObject(IPerceroObject perceroObject) throws SyncException { - - Session s = null; - + public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws SyncException { + + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(theClassIdPair.getClassName()); + IPerceroObject perceroObject = dao.retrieveObject(theClassIdPair, null, false); // Retrieve the full object so we can update the cache if the delete is successful. + Boolean result = dao.deleteObject(theClassIdPair, userId); + try { MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(perceroObject.getClass().getCanonicalName()); if (mappedClass == null) { @@ -1589,19 +763,10 @@ public Boolean systemDeleteObject(IPerceroObject perceroObject) throws SyncExcep throw new SyncException(SyncException.MISSING_MAPPED_CLASS_ERROR, SyncException.MISSING_MAPPED_CLASS_ERROR_CODE ); } - // TODO: Call the DAO for this. - String deleteQueryString = "DELETE FROM " + (StringUtils.hasText(mappedClass.tableSchema) ? mappedClass.tableSchema + "." : "") + mappedClass.tableName + " WHERE ID=:objectId"; - - s = appSessionFactory.openSession(); - Query query = s.createSQLQuery(deleteQueryString); - query.setParameter("objectId", perceroObject.getID()); - - int result = query.executeUpdate(); - // Now delete from cache. // Now update the cache. // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... - if (cacheTimeout > 0) { + if (result && cacheTimeout > 0) { Set keysToDelete = new HashSet(); String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); @@ -1652,13 +817,9 @@ else if (fieldObject instanceof Collection) { if (!keysToDelete.isEmpty()) { cacheDataStore.deleteKeys(keysToDelete); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); } } - return true; - } catch(Exception e) { if (perceroObject != null) { log.error("Unable to delete record from database: " + perceroObject.getClass().getCanonicalName() + ":" + perceroObject.getID(), e); @@ -1667,66 +828,62 @@ else if (fieldObject instanceof Collection) { log.error("Unable to delete record from database: NULL Object", e); } throw new SyncDataException(SyncDataException.DELETE_OBJECT_ERROR, SyncDataException.DELETE_OBJECT_ERROR_CODE); - } finally { - if (s != null && s.isOpen()) { - s.close(); - } } + + return result; } //////////////////////////////////////////////////// // CLEAN //////////////////////////////////////////////////// - @Override + @SuppressWarnings("unchecked") public IPerceroObject cleanObject(IPerceroObject perceroObject, String userId) throws SyncException { - try { - if (((BaseDataObject) perceroObject).getIsClean()) { - perceroObject = findById(BaseDataObject.toClassIdPair(perceroObject), userId); - ((BaseDataObject) perceroObject).setIsClean(true); - } - - } catch(Exception e) { - throw new SyncException(e); - } + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(perceroObject.getClass().getCanonicalName()); + perceroObject = dao.cleanObjectForUser(perceroObject, userId); return perceroObject; - } @Override - @SuppressWarnings("rawtypes") + @SuppressWarnings({ "rawtypes", "unchecked" }) public List cleanObject(List perceroObjects, String userId) throws SyncException { try { List results = new ArrayList(perceroObjects.size()); - Map classPairs = new HashMap(); + Map> classPairs = new HashMap>(); - Iterator itrPerceroObjects = perceroObjects.iterator(); + Iterator itrPerceroObjects = perceroObjects.iterator(); while (itrPerceroObjects.hasNext()) { IPerceroObject nextPerceroObject = itrPerceroObjects.next(); if ( ((BaseDataObject)nextPerceroObject).getIsClean()) { results.add(nextPerceroObject); } else { - ClassIDPairs pairs = classPairs.get(nextPerceroObject.getClass()); - if (pairs == null) { - pairs = new ClassIDPairs(); - pairs.setClassName(nextPerceroObject.getClass().getCanonicalName()); - classPairs.put(nextPerceroObject.getClass(), pairs); + List classObjects = classPairs.get(nextPerceroObject.getClass()); + if (classObjects == null) { + classObjects = new ArrayList(); + classPairs.put(nextPerceroObject.getClass(), classObjects); } - pairs.addId(nextPerceroObject.getID()); + classObjects.add(nextPerceroObject); } } - Iterator> itrClassPairs = classPairs.entrySet().iterator(); + Iterator>> itrClassPairs = classPairs.entrySet().iterator(); while (itrClassPairs.hasNext()) { - Entry nextEntrySet = itrClassPairs.next(); + Entry> nextEntrySet = itrClassPairs.next(); + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(nextEntrySet.getKey().getCanonicalName()); - MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(nextEntrySet.getKey().getCanonicalName()); - if (mappedClass != null) { - results.addAll( mappedClass.getDataProvider().findByIds(nextEntrySet.getValue(), userId) ); + List nextClassObjects = nextEntrySet.getValue(); + if (nextClassObjects != null && !nextClassObjects.isEmpty()) { + Iterator itrClassObjects = nextClassObjects.iterator(); + while (itrClassObjects.hasNext()) { + IPerceroObject nextObject = itrClassObjects.next(); + IPerceroObject nextResult = dao.cleanObjectForUser(nextObject, userId); + if (nextResult != null) { + results.add(nextResult); + } + } } - } return results; @@ -1743,7 +900,7 @@ public Map> getChangedMappedFields(IPercero ClassIDPair basePair = new ClassIDPair(newObject.getID(), newObject.getClass().getCanonicalName()); String className = newObject.getClass().getCanonicalName(); - IPerceroObject oldObject = systemGetById(new ClassIDPair(newObject.getID(), className)); + IPerceroObject oldObject = findById(new ClassIDPair(newObject.getID(), className), null); IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mc = mcm.getMappedClassByClassName(className); Iterator itrMappedFields = mc.externalizableFields.iterator(); @@ -1848,13 +1005,13 @@ private Collection retrieveObjectsNotInCollection(Collection baseList, Collectio while (itrBaseList.hasNext()) { BaseDataObject nextBasePerceroObject = (BaseDataObject) itrBaseList.next(); ClassIDPair nextBasePair = BaseDataObject.toClassIdPair(nextBasePerceroObject); - nextBasePerceroObject = (BaseDataObject) systemGetById(nextBasePair); + nextBasePerceroObject = (BaseDataObject) findById(nextBasePair, null); itrCompareToList = compareToList.iterator(); matchFound = false; while (itrCompareToList.hasNext()) { BaseDataObject nextCompareToPerceroObject = (BaseDataObject) itrCompareToList.next(); - nextCompareToPerceroObject = (BaseDataObject) systemGetById(BaseDataObject.toClassIdPair(nextCompareToPerceroObject)); + nextCompareToPerceroObject = (BaseDataObject) findById(BaseDataObject.toClassIdPair(nextCompareToPerceroObject), null); if (nextBasePerceroObject.getClass() == nextCompareToPerceroObject.getClass() && nextBasePerceroObject.getID().equalsIgnoreCase(nextCompareToPerceroObject.getID())) { matchFound = true; @@ -1874,7 +1031,7 @@ private Collection retrieveObjectsNotInCollection(Collection baseList, Collectio /* (non-Javadoc) * @see com.percero.agents.sync.services.IDataProvider#findAllRelatedObjects(com.percero.framework.vo.IPerceroObject, com.percero.agents.sync.metadata.MappedField, java.lang.Boolean, java.lang.String) */ - @SuppressWarnings("unchecked") + // @Override public List findAllRelatedObjects(IPerceroObject perceroObject, MappedField mappedField, Boolean shellOnly, String userId) throws SyncException { List result = new ArrayList(); @@ -1897,9 +1054,10 @@ public List findAllRelatedObjects(IPerceroObject perceroObject, return result; } + @SuppressWarnings("unchecked") public List getAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException { - IDataAccessObject dao = daoRegistry.getDataAccessObject(mappedField.getMappedClass().className); - return dao.getAllByRelationship(mappedField, targetClassIdPair, shellOnly, userId); + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(mappedField.getMappedClass().className); + return dao.retrieveAllByRelationship(mappedField, targetClassIdPair, shellOnly, userId); } diff --git a/src/main/java/com/percero/agents/sync/services/DAORegistry.java b/src/main/java/com/percero/agents/sync/services/DAORegistry.java deleted file mode 100644 index d97f0e2..0000000 --- a/src/main/java/com/percero/agents/sync/services/DAORegistry.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.percero.agents.sync.services; - -import java.util.HashMap; -import java.util.Map; - -import javax.annotation.PostConstruct; - -import org.springframework.stereotype.Component; - -import com.percero.agents.sync.dao.IDataAccessObject; -import com.percero.framework.vo.IPerceroObject; - -@Component -public class DAORegistry { - - private static DAORegistry instance = null; - - public static DAORegistry getInstance() { - return instance; - } - - public DAORegistry() { - instance = this; - } - - private static Map> dataAccessObjects; - - @PostConstruct - public void init() { - // Init the data access objects here. - dataAccessObjects = new HashMap>(); - } - - public IDataAccessObject getDataAccessObject(String name) { - return dataAccessObjects.get(name); - } -} diff --git a/src/main/java/com/percero/agents/sync/services/DataProviderManager.java b/src/main/java/com/percero/agents/sync/services/DataProviderManager.java index b64419a..b6ee68e 100644 --- a/src/main/java/com/percero/agents/sync/services/DataProviderManager.java +++ b/src/main/java/com/percero/agents/sync/services/DataProviderManager.java @@ -10,6 +10,15 @@ @Component public class DataProviderManager implements IDataProviderManager { + + private static DataProviderManager instance = null; + public static DataProviderManager getInstance() { + return instance; + } + + public DataProviderManager() { + instance = this; + } @Autowired ApplicationContext appContext; diff --git a/src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java b/src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java index a0708fc..b962733 100644 --- a/src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java @@ -1,1688 +1,1688 @@ -package com.percero.agents.sync.services; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtField; -import javassist.CtMethod; - -import org.apache.log4j.Logger; -import org.codehaus.jackson.map.ObjectMapper; -import org.hibernate.Criteria; -import org.hibernate.PropertyValueException; -import org.hibernate.Query; -import org.hibernate.QueryException; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; -import org.hibernate.criterion.Criterion; -import org.hibernate.criterion.MatchMode; -import org.hibernate.criterion.Restrictions; -import org.hibernate.impl.SessionImpl; -import org.hibernate.type.Type; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -import com.percero.agents.sync.access.RedisKeyUtils; -import com.percero.agents.sync.datastore.ICacheDataStore; -import com.percero.agents.sync.exceptions.SyncDataException; -import com.percero.agents.sync.exceptions.SyncException; -import com.percero.agents.sync.hibernate.AssociationExample; -import com.percero.agents.sync.hibernate.BaseDataObjectPropertySelector; -import com.percero.agents.sync.hibernate.SyncHibernateUtils; -import com.percero.agents.sync.metadata.IMappedClassManager; -import com.percero.agents.sync.metadata.JpqlQuery; -import com.percero.agents.sync.metadata.MappedClass; -import com.percero.agents.sync.metadata.MappedClassManagerFactory; -import com.percero.agents.sync.metadata.MappedField; -import com.percero.agents.sync.metadata.MappedFieldList; -import com.percero.agents.sync.metadata.MappedFieldMap; -import com.percero.agents.sync.metadata.MappedFieldPerceroObject; -import com.percero.agents.sync.vo.BaseDataObject; -import com.percero.agents.sync.vo.ClassIDPair; -import com.percero.agents.sync.vo.ClassIDPairs; -import com.percero.agents.sync.vo.IJsonObject; -import com.percero.agents.sync.vo.IRootObject; -import com.percero.framework.metadata.IMappedQuery; -import com.percero.framework.vo.IPerceroObject; -import com.percero.framework.vo.PerceroList; - -@Component -public class HibernateDataProvider implements IDataProvider { - - // TODO: Better manage Hibernate Sessions (opening and closing). - - private static final Logger log = Logger.getLogger(HibernateDataProvider.class); - - public void initialize() - { - // Do nothing. - } - - public String getName() { - return "syncAgent"; - } - - @Autowired - ICacheDataStore cacheDataStore; - - @Autowired - Long cacheTimeout = Long.valueOf(60 * 60 * 24 * 14); // Two weeks - - @Autowired - ObjectMapper safeObjectMapper; - - @Autowired - SessionFactory appSessionFactory; - public void setAppSessionFactory(SessionFactory value) { - appSessionFactory = value; - } - - - @SuppressWarnings({ "rawtypes", "unchecked" }) - // TODO: @Transactional(readOnly=true) - public PerceroList getAllByName(Object aName, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception { - Session s = appSessionFactory.openSession(); - try { - returnTotal = true; - String aClassName = aName.toString(); - Query countQuery = null; - Query query = null; - Class theClass = MappedClass.forName(aName.toString()); - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); - boolean isValidReadQuery = false; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - isValidReadQuery = true; - } - } - - /** - * readAllQuery optimization - * You can now define a readAllQuery on a class to imporove it's initial download time - * for briefcase mode. - * - * Only supports plain SQL for now - */ - if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ - if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ - throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); - } - - log.debug("Using readAllQuery: "+aClassName); - String selectQueryString = mappedClass.getReadAllQuery().getQuery(); - - String countQueryString = "select count(*) from ("+selectQueryString+") as U"; - - // Add the limit clause - if (pageSize != null && pageNumber != null && pageSize.intValue() > 0) { - int offset = pageSize.intValue() * pageNumber.intValue(); - selectQueryString += " limit "+pageSize+" OFFSET "+offset; - } - - query = s.createSQLQuery(selectQueryString).addEntity(theClass); - countQuery = s.createSQLQuery(countQueryString); - - query.setParameter("userId", userId); - countQuery.setParameter("userId", userId); - } - else - if (theClass != null) { - String countQueryString = ""; - if (returnTotal) - countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; - String queryString = "SELECT getAllResult FROM " + aClassName + " getAllResult"; - - // If the Read Query/Filter uses the ID, then we need to check against each ID here. - if (isValidReadQuery) { - String queryFilterString = mappedClass.getReadQuery().getQuery(); - if (mappedClass.getReadQuery().getUseId()) { - // Need to replace :id with - queryFilterString = queryFilterString.replaceAll(":id", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":Id", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":iD", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":ID", "getAllResult.ID"); - } - String countQueryFilterString = ""; - if (returnTotal) - countQueryFilterString = queryFilterString; - queryFilterString = queryString + " WHERE (" + queryFilterString + ") > 0 ORDER BY getAllResult.ID"; - - if (returnTotal) { - countQueryFilterString = countQueryString + " WHERE (" + countQueryFilterString + ") > 0"; - countQuery = s.createQuery(countQueryFilterString); - } - query = s.createQuery(queryFilterString); - mappedClass.getReadQuery().setQueryParameters(query, null, userId); - mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); - } - else { - queryString += " ORDER BY getAllResult.ID"; - if (returnTotal) { - countQueryString += " ORDER BY ID"; - countQuery = s.createQuery(countQueryString); - } - query = s.createQuery(queryString); - } - if (pageSize != null && pageNumber != null && pageSize.intValue() > 0) { - int pageValue = pageSize.intValue() * pageNumber.intValue(); - query.setFirstResult(pageValue); - query.setMaxResults(pageSize.intValue()); - } - } - - if (query != null) { - - log.debug("Get ALL: "+aClassName); - long t1 = new Date().getTime(); - List list = query.list(); - long t2 = new Date().getTime(); - log.debug("Query Time: "+(t2-t1)); - PerceroList result = new PerceroList( (List) SyncHibernateUtils.cleanObject(list, s, userId) ); - long t3 = new Date().getTime(); - log.debug("Clean Time: "+(t3-t2)); - - result.setPageNumber(pageNumber); - result.setPageSize(pageSize); - - if (returnTotal && pageSize != null && pageNumber != null && pageSize.intValue() > 0){ - result.setTotalLength(((Number)countQuery.uniqueResult()).intValue()); - log.debug("Total Obs: "+result.getTotalLength()); - } - else - result.setTotalLength(result.size()); - return result; - } - else { - return null; - } - - } catch (Exception e) { - log.error("Unable to getAllByName", e); - } finally { - s.close(); - } - - return null; - } - - @SuppressWarnings({ "rawtypes" }) - // TODO: @Transactional(readOnly=true) - public Integer countAllByName(String aClassName, String userId) throws Exception { - Session s = appSessionFactory.openSession(); - try { - Query countQuery = null; - Class theClass = MappedClass.forName(aClassName); - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); - boolean isValidReadQuery = false; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - isValidReadQuery = true; - } - } - - if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ - if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ - throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); - } - - String selectQueryString = mappedClass.getReadAllQuery().getQuery(); - - String countQueryString = "select count(*) from ("+selectQueryString+") as U"; - - countQuery = s.createSQLQuery(countQueryString); - countQuery.setParameter("userId", userId); - } - else if (theClass != null) { - String countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; - - // If the Read Query/Filter uses the ID, then we need to check against each ID here. - if (isValidReadQuery) { - String queryFilterString = mappedClass.getReadQuery().getQuery(); - if (mappedClass.getReadQuery().getUseId()) { - // Need to replace :id with - queryFilterString = queryFilterString.replaceAll(":id", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":Id", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":iD", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":ID", "getAllResult.ID"); - } - String countQueryFilterString = queryFilterString; - countQueryFilterString = countQueryString + " WHERE (" + countQueryFilterString + ") > 0"; - - countQuery = s.createQuery(countQueryFilterString); - mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); - } - else { - countQueryString += " ORDER BY ID"; - countQuery = s.createQuery(countQueryString); - } - } - - if (countQuery != null) { -// log.debug(countQuery.toString()); - Integer result = ((Number)countQuery.uniqueResult()).intValue(); - return result; - } - else { - return null; - } - - } catch (Exception e) { - log.error("Unable to countAllByName", e); - } finally { - s.close(); - } - - return 0; - } - - public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String userId) { - Session s = appSessionFactory.openSession(); - try { - if (mappedClass != null) { - for(IMappedQuery nextQuery : mappedClass.queries) - { - if (queryName.equalsIgnoreCase(nextQuery.getQueryName())) - { - Query readFilter = s.createQuery(nextQuery.getQuery()); - nextQuery.setQueryParameters(readFilter, queryArguments, userId, queryArguments, (SessionImpl)s); - return processQueryResults(mappedClass.className + "_" + queryName, readFilter, readFilter.list()); - } - } - } - } catch (Exception e) { - log.error("Unable to runQuery", e); - } finally { - if (s != null && s.isOpen()) - s.close(); - } - - return null; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - protected static List processQueryResults(String resultClassName, Query updateFilter, List updateFilterResult) throws Exception { - String[] returnAliases = updateFilter.getReturnAliases(); - Type[] returnTypes = updateFilter.getReturnTypes(); - - String[] fieldNames = new String[returnAliases.length]; - String[] getMethodNames = new String[returnAliases.length]; - String[] setMethodNames = new String[returnAliases.length]; - Class[] fieldClasses = new Class[returnAliases.length]; - - Class clazz = null; - ClassPool pool = null; - CtClass evalClass = null; - - if (returnAliases.length > 1) { - try { - clazz = MappedClass.forName(resultClassName); - } catch(Exception e) { - // Class must not yet exist, so let's create it. - } - - if (clazz == null) { - pool = ClassPool.getDefault(); - evalClass = pool.makeClass(resultClassName); - } - - // Create a new Class based on the result set. - for(int i = 0; i < returnAliases.length; i++) { - Type nextType = returnTypes[i]; - String nextTypeCanonicalName = nextType.getReturnedClass().getCanonicalName(); - String nextFieldName = returnAliases[i]; - try { - Integer.parseInt(nextFieldName); - nextFieldName = "field" + i; - } catch(NumberFormatException nfe) { - // Do nothing. Simply means the field name is not a Number. - } - String nextUpperFieldName = nextFieldName.substring(0, 1).toUpperCase() + nextFieldName.substring(1); - - fieldNames[i] = nextFieldName; - getMethodNames[i] = "get" + nextUpperFieldName; - setMethodNames[i] = "set" + nextUpperFieldName; - fieldClasses[i] = nextType.getReturnedClass(); - - if (evalClass != null) { - evalClass.addField(CtField.make("private " + fieldClasses[i].getCanonicalName() + " " + nextFieldName + ";", evalClass)); - evalClass.addMethod(CtMethod.make("public void " + setMethodNames[i] + "(" + fieldClasses[i].getCanonicalName() + " value) {this." + nextFieldName + " = value;}", evalClass)); - evalClass.addMethod(CtMethod.make("public " + nextTypeCanonicalName +" " + getMethodNames[i] + "() {return this." + nextFieldName + ";}", evalClass)); - } - } - - if (clazz == null && evalClass != null) { - clazz = evalClass.toClass(); - } - } - - List results = new ArrayList(); - - // Now populate the newly created objects. - for(Object nextResult : (List)updateFilterResult) { - - if (nextResult instanceof Object[]) { - Object nextObject = clazz.newInstance(); - for(int i = 0; i < returnAliases.length; i++) { - Class[] formalParams = new Class[] { fieldClasses[i] }; - Method setMethod = clazz.getDeclaredMethod(setMethodNames[i], formalParams); - setMethod.invoke(nextObject, ((Object[])nextResult)[i]); - } - - results.add(nextObject); - } else - results.add(nextResult); - } - - return results; - } - - //@SuppressWarnings({ "rawtypes", "unchecked" }) - public IPerceroObject findById(ClassIDPair classIdPair, String userId) { - boolean hasReadQuery = false; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - hasReadQuery = true; - } - } - - Session s = null; - try { - boolean hasAccess = true; - IPerceroObject result = systemGetById(classIdPair); - - if (result != null) { - if (hasReadQuery) { - if (s == null) - s = appSessionFactory.openSession(); - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - - if (hasAccess) { - if (s == null) - s = appSessionFactory.openSession(); -// ((BaseDataObject)result).setIsClean(false); - result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s, userId); - return result; - } - else { - return null; - } - } - else { - return null; - } - } catch (Exception e) { - log.error("Unable to findById", e); - } finally { - if (s != null && s.isOpen()) - s.close(); - } - return null; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public IPerceroObject systemGetById(ClassIDPair classIdPair) { - Session s = null; - try { - Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); - - if (theClass != null) { - IPerceroObject result = retrieveFromRedisCache(classIdPair); - String key = null; - - if (result == null) { - s = appSessionFactory.openSession(); - result = (IPerceroObject) s.get(theClass, classIdPair.getID()); - - // Now put the object in the cache. - if (result != null) { - key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); - result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); - if (cacheTimeout > 0) - cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); - } - else { - // Not necessarily a problem but could be helpful when debugging. - log.debug("Unable to retrieve object from database: " + classIdPair.toJson()); - } - } - else { - key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); - } - - // (Re)Set the expiration. - if (cacheTimeout > 0 && key != null) { - cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); - } - - return result; - } else { - return null; - } - } catch (Exception e) { - log.error("Unable to systemGetById: "+classIdPair.toJson(), e); - } finally { - if (s != null && s.isOpen()) - s.close(); - } - return null; - } - - @SuppressWarnings({ "rawtypes" }) - public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, Class theClass, Session s) { - Boolean sessionAlreadyOpen = false; - try { - if (theClass != null) { - IPerceroObject result = retrieveFromRedisCache(classIdPair); - String key = null; - - if (result == null) { - if (s == null || !s.isOpen()) { - s = appSessionFactory.openSession(); - } - else { - sessionAlreadyOpen = true; - } - result = (IPerceroObject) s.get(theClass, classIdPair.getID()); - - // Now put the object in the cache. - if (result != null) { - key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); - result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); - if (cacheTimeout > 0) - cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); - } - else { - log.warn("Unable to retrieve object from database: " + classIdPair.toString()); - } - } - else { - key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); - } - - // (Re)Set the expiration. - if (cacheTimeout > 0 && key != null) { - cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); - } - - return result; - } else { - return null; - } - } catch (Exception e) { - log.error("Unable to systemGetById: "+classIdPair.toJson(), e); - } finally { - // Only close the session if it wasn't already open. - if (!sessionAlreadyOpen) { - if (s != null && s.isOpen()) { - s.close(); - } - } - } - return null; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Exception { - IPerceroObject result = null; - if (cacheTimeout > 0) { - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - Class theClass = MappedClass.forName(classIdPair.getClassName()); - MappedClass mc = mcm.getMappedClassByClassName(classIdPair.getClassName()); - - String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); - String jsonObjectString = (String) cacheDataStore.getValue(key); - if (jsonObjectString != null) { - if (IJsonObject.class.isAssignableFrom(theClass)) { - IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); - jsonObject.fromJson(jsonObjectString); - result = (IPerceroObject) jsonObject; - } - else { - result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); - } - } - else { - // Check MappedClass' child classes. - Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); - while (itrChildMappedClasses.hasNext()) { - MappedClass nextChildMc = itrChildMappedClasses.next(); - key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); - jsonObjectString = (String) cacheDataStore.getValue(key); - if (jsonObjectString != null) { - result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); - return result; - } - } - } - } - - return result; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private Map retrieveFromRedisCache(ClassIDPairs classIdPairs, Boolean pleaseSetTimeout) throws Exception { - Map result = new HashMap(classIdPairs.getIds().size()); - - if (cacheTimeout > 0) { - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - Class theClass = MappedClass.forName(classIdPairs.getClassName()); - MappedClass mc = mcm.getMappedClassByClassName(classIdPairs.getClassName()); - - Set keys = new HashSet(classIdPairs.getIds().size()); - Iterator itrIds = classIdPairs.getIds().iterator(); - while (itrIds.hasNext()) { - String nextId = itrIds.next(); - String nextKey = RedisKeyUtils.classIdPair(classIdPairs.getClassName(), nextId); - keys.add(nextKey); - - // Check MappedClass' child classes. - Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); - while (itrChildMappedClasses.hasNext()) { - MappedClass nextChildMc = itrChildMappedClasses.next(); - if (nextChildMc.clazz == BaseDataObject.class) { - // Reached the top level, so break. - break; - } - nextKey = RedisKeyUtils.classIdPair(nextChildMc.className, nextId); - keys.add(nextKey); - } - } - +//package com.percero.agents.sync.services; +// +//import java.lang.reflect.Method; +//import java.util.ArrayList; +//import java.util.Collection; +//import java.util.Date; +//import java.util.HashMap; +//import java.util.HashSet; +//import java.util.Iterator; +//import java.util.List; +//import java.util.Map; +//import java.util.Set; +//import java.util.UUID; +//import java.util.concurrent.TimeUnit; +// +//import javassist.ClassPool; +//import javassist.CtClass; +//import javassist.CtField; +//import javassist.CtMethod; +// +//import org.apache.log4j.Logger; +//import org.codehaus.jackson.map.ObjectMapper; +//import org.hibernate.Criteria; +//import org.hibernate.PropertyValueException; +//import org.hibernate.Query; +//import org.hibernate.QueryException; +//import org.hibernate.Session; +//import org.hibernate.SessionFactory; +//import org.hibernate.Transaction; +//import org.hibernate.criterion.Criterion; +//import org.hibernate.criterion.MatchMode; +//import org.hibernate.criterion.Restrictions; +//import org.hibernate.impl.SessionImpl; +//import org.hibernate.type.Type; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.stereotype.Component; +//import org.springframework.util.StringUtils; +// +//import com.percero.agents.sync.access.RedisKeyUtils; +//import com.percero.agents.sync.datastore.ICacheDataStore; +//import com.percero.agents.sync.exceptions.SyncDataException; +//import com.percero.agents.sync.exceptions.SyncException; +//import com.percero.agents.sync.hibernate.AssociationExample; +//import com.percero.agents.sync.hibernate.BaseDataObjectPropertySelector; +//import com.percero.agents.sync.hibernate.SyncHibernateUtils; +//import com.percero.agents.sync.metadata.IMappedClassManager; +//import com.percero.agents.sync.metadata.JpqlQuery; +//import com.percero.agents.sync.metadata.MappedClass; +//import com.percero.agents.sync.metadata.MappedClassManagerFactory; +//import com.percero.agents.sync.metadata.MappedField; +//import com.percero.agents.sync.metadata.MappedFieldList; +//import com.percero.agents.sync.metadata.MappedFieldMap; +//import com.percero.agents.sync.metadata.MappedFieldPerceroObject; +//import com.percero.agents.sync.vo.BaseDataObject; +//import com.percero.agents.sync.vo.ClassIDPair; +//import com.percero.agents.sync.vo.ClassIDPairs; +//import com.percero.agents.sync.vo.IJsonObject; +//import com.percero.agents.sync.vo.IRootObject; +//import com.percero.framework.metadata.IMappedQuery; +//import com.percero.framework.vo.IPerceroObject; +//import com.percero.framework.vo.PerceroList; +// +//@Component +//public class HibernateDataProvider implements IDataProvider { +// +// // TODO: Better manage Hibernate Sessions (opening and closing). +// +// private static final Logger log = Logger.getLogger(HibernateDataProvider.class); +// +// public void initialize() +// { +// // Do nothing. +// } +// +// public String getName() { +// return "syncAgent"; +// } +// +// @Autowired +// ICacheDataStore cacheDataStore; +// +// @Autowired +// Long cacheTimeout = Long.valueOf(60 * 60 * 24 * 14); // Two weeks +// +// @Autowired +// ObjectMapper safeObjectMapper; +// +// @Autowired +// SessionFactory appSessionFactory; +// public void setAppSessionFactory(SessionFactory value) { +// appSessionFactory = value; +// } +// +// +// @SuppressWarnings({ "rawtypes", "unchecked" }) +// // TODO: @Transactional(readOnly=true) +// public PerceroList getAllByName(Object aName, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception { +// Session s = appSessionFactory.openSession(); +// try { +// returnTotal = true; +// String aClassName = aName.toString(); +// Query countQuery = null; +// Query query = null; +// Class theClass = MappedClass.forName(aName.toString()); +// +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); +// boolean isValidReadQuery = false; +// if (mappedClass != null) { +// if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { +// isValidReadQuery = true; +// } +// } +// +// /** +// * readAllQuery optimization +// * You can now define a readAllQuery on a class to imporove it's initial download time +// * for briefcase mode. +// * +// * Only supports plain SQL for now +// */ +// if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ +// if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ +// throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); +// } +// +// log.debug("Using readAllQuery: "+aClassName); +// String selectQueryString = mappedClass.getReadAllQuery().getQuery(); +// +// String countQueryString = "select count(*) from ("+selectQueryString+") as U"; +// +// // Add the limit clause +// if (pageSize != null && pageNumber != null && pageSize.intValue() > 0) { +// int offset = pageSize.intValue() * pageNumber.intValue(); +// selectQueryString += " limit "+pageSize+" OFFSET "+offset; +// } +// +// query = s.createSQLQuery(selectQueryString).addEntity(theClass); +// countQuery = s.createSQLQuery(countQueryString); +// +// query.setParameter("userId", userId); +// countQuery.setParameter("userId", userId); +// } +// else +// if (theClass != null) { +// String countQueryString = ""; +// if (returnTotal) +// countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; +// String queryString = "SELECT getAllResult FROM " + aClassName + " getAllResult"; +// +// // If the Read Query/Filter uses the ID, then we need to check against each ID here. +// if (isValidReadQuery) { +// String queryFilterString = mappedClass.getReadQuery().getQuery(); +// if (mappedClass.getReadQuery().getUseId()) { +// // Need to replace :id with +// queryFilterString = queryFilterString.replaceAll(":id", "getAllResult.ID"); +// queryFilterString = queryFilterString.replaceAll(":Id", "getAllResult.ID"); +// queryFilterString = queryFilterString.replaceAll(":iD", "getAllResult.ID"); +// queryFilterString = queryFilterString.replaceAll(":ID", "getAllResult.ID"); +// } +// String countQueryFilterString = ""; +// if (returnTotal) +// countQueryFilterString = queryFilterString; +// queryFilterString = queryString + " WHERE (" + queryFilterString + ") > 0 ORDER BY getAllResult.ID"; +// +// if (returnTotal) { +// countQueryFilterString = countQueryString + " WHERE (" + countQueryFilterString + ") > 0"; +// countQuery = s.createQuery(countQueryFilterString); +// } +// query = s.createQuery(queryFilterString); +// mappedClass.getReadQuery().setQueryParameters(query, null, userId); +// mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); +// } +// else { +// queryString += " ORDER BY getAllResult.ID"; +// if (returnTotal) { +// countQueryString += " ORDER BY ID"; +// countQuery = s.createQuery(countQueryString); +// } +// query = s.createQuery(queryString); +// } +// if (pageSize != null && pageNumber != null && pageSize.intValue() > 0) { +// int pageValue = pageSize.intValue() * pageNumber.intValue(); +// query.setFirstResult(pageValue); +// query.setMaxResults(pageSize.intValue()); +// } +// } +// +// if (query != null) { +// +// log.debug("Get ALL: "+aClassName); +// long t1 = new Date().getTime(); +// List list = query.list(); +// long t2 = new Date().getTime(); +// log.debug("Query Time: "+(t2-t1)); +// PerceroList result = new PerceroList( (List) SyncHibernateUtils.cleanObject(list, s, userId) ); +// long t3 = new Date().getTime(); +// log.debug("Clean Time: "+(t3-t2)); +// +// result.setPageNumber(pageNumber); +// result.setPageSize(pageSize); +// +// if (returnTotal && pageSize != null && pageNumber != null && pageSize.intValue() > 0){ +// result.setTotalLength(((Number)countQuery.uniqueResult()).intValue()); +// log.debug("Total Obs: "+result.getTotalLength()); +// } +// else +// result.setTotalLength(result.size()); +// return result; +// } +// else { +// return null; +// } +// +// } catch (Exception e) { +// log.error("Unable to getAllByName", e); +// } finally { +// s.close(); +// } +// +// return null; +// } +// +// @SuppressWarnings({ "rawtypes" }) +// // TODO: @Transactional(readOnly=true) +// public Integer countAllByName(String aClassName, String userId) throws Exception { +// Session s = appSessionFactory.openSession(); +// try { +// Query countQuery = null; +// Class theClass = MappedClass.forName(aClassName); +// +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); +// boolean isValidReadQuery = false; +// if (mappedClass != null) { +// if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { +// isValidReadQuery = true; +// } +// } +// +// if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ +// if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ +// throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); +// } +// +// String selectQueryString = mappedClass.getReadAllQuery().getQuery(); +// +// String countQueryString = "select count(*) from ("+selectQueryString+") as U"; +// +// countQuery = s.createSQLQuery(countQueryString); +// countQuery.setParameter("userId", userId); +// } +// else if (theClass != null) { +// String countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; +// +// // If the Read Query/Filter uses the ID, then we need to check against each ID here. +// if (isValidReadQuery) { +// String queryFilterString = mappedClass.getReadQuery().getQuery(); +// if (mappedClass.getReadQuery().getUseId()) { +// // Need to replace :id with +// queryFilterString = queryFilterString.replaceAll(":id", "getAllResult.ID"); +// queryFilterString = queryFilterString.replaceAll(":Id", "getAllResult.ID"); +// queryFilterString = queryFilterString.replaceAll(":iD", "getAllResult.ID"); +// queryFilterString = queryFilterString.replaceAll(":ID", "getAllResult.ID"); +// } +// String countQueryFilterString = queryFilterString; +// countQueryFilterString = countQueryString + " WHERE (" + countQueryFilterString + ") > 0"; +// +// countQuery = s.createQuery(countQueryFilterString); +// mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); +// } +// else { +// countQueryString += " ORDER BY ID"; +// countQuery = s.createQuery(countQueryString); +// } +// } +// +// if (countQuery != null) { +//// log.debug(countQuery.toString()); +// Integer result = ((Number)countQuery.uniqueResult()).intValue(); +// return result; +// } +// else { +// return null; +// } +// +// } catch (Exception e) { +// log.error("Unable to countAllByName", e); +// } finally { +// s.close(); +// } +// +// return 0; +// } +// +// public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String userId) { +// Session s = appSessionFactory.openSession(); +// try { +// if (mappedClass != null) { +// for(IMappedQuery nextQuery : mappedClass.queries) +// { +// if (queryName.equalsIgnoreCase(nextQuery.getQueryName())) +// { +// Query readFilter = s.createQuery(nextQuery.getQuery()); +// nextQuery.setQueryParameters(readFilter, queryArguments, userId, queryArguments, (SessionImpl)s); +// return processQueryResults(mappedClass.className + "_" + queryName, readFilter, readFilter.list()); +// } +// } +// } +// } catch (Exception e) { +// log.error("Unable to runQuery", e); +// } finally { +// if (s != null && s.isOpen()) +// s.close(); +// } +// +// return null; +// } +// +// @SuppressWarnings({ "rawtypes", "unchecked" }) +// protected static List processQueryResults(String resultClassName, Query updateFilter, List updateFilterResult) throws Exception { +// String[] returnAliases = updateFilter.getReturnAliases(); +// Type[] returnTypes = updateFilter.getReturnTypes(); +// +// String[] fieldNames = new String[returnAliases.length]; +// String[] getMethodNames = new String[returnAliases.length]; +// String[] setMethodNames = new String[returnAliases.length]; +// Class[] fieldClasses = new Class[returnAliases.length]; +// +// Class clazz = null; +// ClassPool pool = null; +// CtClass evalClass = null; +// +// if (returnAliases.length > 1) { +// try { +// clazz = MappedClass.forName(resultClassName); +// } catch(Exception e) { +// // Class must not yet exist, so let's create it. +// } +// +// if (clazz == null) { +// pool = ClassPool.getDefault(); +// evalClass = pool.makeClass(resultClassName); +// } +// +// // Create a new Class based on the result set. +// for(int i = 0; i < returnAliases.length; i++) { +// Type nextType = returnTypes[i]; +// String nextTypeCanonicalName = nextType.getReturnedClass().getCanonicalName(); +// String nextFieldName = returnAliases[i]; +// try { +// Integer.parseInt(nextFieldName); +// nextFieldName = "field" + i; +// } catch(NumberFormatException nfe) { +// // Do nothing. Simply means the field name is not a Number. +// } +// String nextUpperFieldName = nextFieldName.substring(0, 1).toUpperCase() + nextFieldName.substring(1); +// +// fieldNames[i] = nextFieldName; +// getMethodNames[i] = "get" + nextUpperFieldName; +// setMethodNames[i] = "set" + nextUpperFieldName; +// fieldClasses[i] = nextType.getReturnedClass(); +// +// if (evalClass != null) { +// evalClass.addField(CtField.make("private " + fieldClasses[i].getCanonicalName() + " " + nextFieldName + ";", evalClass)); +// evalClass.addMethod(CtMethod.make("public void " + setMethodNames[i] + "(" + fieldClasses[i].getCanonicalName() + " value) {this." + nextFieldName + " = value;}", evalClass)); +// evalClass.addMethod(CtMethod.make("public " + nextTypeCanonicalName +" " + getMethodNames[i] + "() {return this." + nextFieldName + ";}", evalClass)); +// } +// } +// +// if (clazz == null && evalClass != null) { +// clazz = evalClass.toClass(); +// } +// } +// +// List results = new ArrayList(); +// +// // Now populate the newly created objects. +// for(Object nextResult : (List)updateFilterResult) { +// +// if (nextResult instanceof Object[]) { +// Object nextObject = clazz.newInstance(); +// for(int i = 0; i < returnAliases.length; i++) { +// Class[] formalParams = new Class[] { fieldClasses[i] }; +// Method setMethod = clazz.getDeclaredMethod(setMethodNames[i], formalParams); +// setMethod.invoke(nextObject, ((Object[])nextResult)[i]); +// } +// +// results.add(nextObject); +// } else +// results.add(nextResult); +// } +// +// return results; +// } +// +// //@SuppressWarnings({ "rawtypes", "unchecked" }) +// public IPerceroObject findById(ClassIDPair classIdPair, String userId) { +// boolean hasReadQuery = false; +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); +// if (mappedClass != null) { +// if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { +// hasReadQuery = true; +// } +// } +// +// Session s = null; +// try { +// boolean hasAccess = true; +// IPerceroObject result = systemGetById(classIdPair); +// +// if (result != null) { +// if (hasReadQuery) { +// if (s == null) +// s = appSessionFactory.openSession(); +// Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); +// mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); +// Number readFilterResult = (Number) readFilter.uniqueResult(); +// if (readFilterResult == null || readFilterResult.intValue() <= 0) +// hasAccess = false; +// } +// +// if (hasAccess) { +// if (s == null) +// s = appSessionFactory.openSession(); +//// ((BaseDataObject)result).setIsClean(false); +// result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s, userId); +// return result; +// } +// else { +// return null; +// } +// } +// else { +// return null; +// } +// } catch (Exception e) { +// log.error("Unable to findById", e); +// } finally { +// if (s != null && s.isOpen()) +// s.close(); +// } +// return null; +// } +// +// @SuppressWarnings({ "rawtypes", "unchecked" }) +// public IPerceroObject systemGetById(ClassIDPair classIdPair) { +// Session s = null; +// try { +// Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); +// +// if (theClass != null) { +// IPerceroObject result = retrieveFromRedisCache(classIdPair); +// String key = null; +// +// if (result == null) { +// s = appSessionFactory.openSession(); +// result = (IPerceroObject) s.get(theClass, classIdPair.getID()); +// +// // Now put the object in the cache. +// if (result != null) { +// key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); +// result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); +// if (cacheTimeout > 0) +// cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); +// } +// else { +// // Not necessarily a problem but could be helpful when debugging. +// log.debug("Unable to retrieve object from database: " + classIdPair.toJson()); +// } +// } +// else { +// key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); +// } +// +// // (Re)Set the expiration. +// if (cacheTimeout > 0 && key != null) { +// cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); +// } +// +// return result; +// } else { +// return null; +// } +// } catch (Exception e) { +// log.error("Unable to systemGetById: "+classIdPair.toJson(), e); +// } finally { +// if (s != null && s.isOpen()) +// s.close(); +// } +// return null; +// } +// +// @SuppressWarnings({ "rawtypes" }) +// public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, Class theClass, Session s) { +// Boolean sessionAlreadyOpen = false; +// try { +// if (theClass != null) { +// IPerceroObject result = retrieveFromRedisCache(classIdPair); +// String key = null; +// +// if (result == null) { +// if (s == null || !s.isOpen()) { +// s = appSessionFactory.openSession(); +// } +// else { +// sessionAlreadyOpen = true; +// } +// result = (IPerceroObject) s.get(theClass, classIdPair.getID()); +// +// // Now put the object in the cache. +// if (result != null) { +// key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); +// result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); +// if (cacheTimeout > 0) +// cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); +// } +// else { +// log.warn("Unable to retrieve object from database: " + classIdPair.toString()); +// } +// } +// else { +// key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); +// } +// +// // (Re)Set the expiration. +// if (cacheTimeout > 0 && key != null) { +// cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); +// } +// +// return result; +// } else { +// return null; +// } +// } catch (Exception e) { +// log.error("Unable to systemGetById: "+classIdPair.toJson(), e); +// } finally { +// // Only close the session if it wasn't already open. +// if (!sessionAlreadyOpen) { +// if (s != null && s.isOpen()) { +// s.close(); +// } +// } +// } +// return null; +// } +// +// @SuppressWarnings({ "rawtypes", "unchecked" }) +// private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Exception { +// IPerceroObject result = null; +// if (cacheTimeout > 0) { +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// Class theClass = MappedClass.forName(classIdPair.getClassName()); +// MappedClass mc = mcm.getMappedClassByClassName(classIdPair.getClassName()); +// // String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); - List jsonObjectStrings = cacheDataStore.getValues(keys); - Iterator itrJsonObjectStrings = jsonObjectStrings.iterator(); - while (itrJsonObjectStrings.hasNext()) { - String jsonObjectString = (String) itrJsonObjectStrings.next(); - if (jsonObjectString != null) { - if (IJsonObject.class.isAssignableFrom(theClass)) { - IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); - jsonObject.fromJson(jsonObjectString); - result.put( (((IPerceroObject) jsonObject).getID()), (IPerceroObject) jsonObject ); - } - else { - IPerceroObject nextPerceroObject = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); - result.put( nextPerceroObject.getID(), nextPerceroObject); - } - - } +// String jsonObjectString = (String) cacheDataStore.getValue(key); +// if (jsonObjectString != null) { +// if (IJsonObject.class.isAssignableFrom(theClass)) { +// IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); +// jsonObject.fromJson(jsonObjectString); +// result = (IPerceroObject) jsonObject; +// } // else { -// // Check MappedClass' child classes. -// Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); -// while (itrChildMappedClasses.hasNext()) { -// MappedClass nextChildMc = itrChildMappedClasses.next(); -// key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); -// jsonObjectString = (String) redisDataStore.getValue(key); -// if (jsonObjectString != null) { -// result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); -// return result; +// result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); +// } +// } +// else { +// // Check MappedClass' child classes. +// Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); +// while (itrChildMappedClasses.hasNext()) { +// MappedClass nextChildMc = itrChildMappedClasses.next(); +// key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); +// jsonObjectString = (String) cacheDataStore.getValue(key); +// if (jsonObjectString != null) { +// result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); +// return result; +// } +// } +// } +// } +// +// return result; +// } +// +// @SuppressWarnings({ "rawtypes", "unchecked" }) +// private Map retrieveFromRedisCache(ClassIDPairs classIdPairs, Boolean pleaseSetTimeout) throws Exception { +// Map result = new HashMap(classIdPairs.getIds().size()); +// +// if (cacheTimeout > 0) { +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// Class theClass = MappedClass.forName(classIdPairs.getClassName()); +// MappedClass mc = mcm.getMappedClassByClassName(classIdPairs.getClassName()); +// +// Set keys = new HashSet(classIdPairs.getIds().size()); +// Iterator itrIds = classIdPairs.getIds().iterator(); +// while (itrIds.hasNext()) { +// String nextId = itrIds.next(); +// String nextKey = RedisKeyUtils.classIdPair(classIdPairs.getClassName(), nextId); +// keys.add(nextKey); +// +// // Check MappedClass' child classes. +// Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); +// while (itrChildMappedClasses.hasNext()) { +// MappedClass nextChildMc = itrChildMappedClasses.next(); +// if (nextChildMc.clazz == BaseDataObject.class) { +// // Reached the top level, so break. +// break; +// } +// nextKey = RedisKeyUtils.classIdPair(nextChildMc.className, nextId); +// keys.add(nextKey); +// } +// } +// +//// String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); +// List jsonObjectStrings = cacheDataStore.getValues(keys); +// Iterator itrJsonObjectStrings = jsonObjectStrings.iterator(); +// while (itrJsonObjectStrings.hasNext()) { +// String jsonObjectString = (String) itrJsonObjectStrings.next(); +// if (jsonObjectString != null) { +// if (IJsonObject.class.isAssignableFrom(theClass)) { +// IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); +// jsonObject.fromJson(jsonObjectString); +// result.put( (((IPerceroObject) jsonObject).getID()), (IPerceroObject) jsonObject ); +// } +// else { +// IPerceroObject nextPerceroObject = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); +// result.put( nextPerceroObject.getID(), nextPerceroObject); +// } +// +// } +//// else { +//// // Check MappedClass' child classes. +//// Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); +//// while (itrChildMappedClasses.hasNext()) { +//// MappedClass nextChildMc = itrChildMappedClasses.next(); +//// key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); +//// jsonObjectString = (String) redisDataStore.getValue(key); +//// if (jsonObjectString != null) { +//// result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); +//// return result; +//// } +//// } +//// } +// } +// +// if (pleaseSetTimeout) { +// cacheDataStore.expire(keys, cacheTimeout, TimeUnit.SECONDS); +// } +// } +// +// return result; +// } +// +// @SuppressWarnings({ "rawtypes" }) +// public Boolean getReadAccess(ClassIDPair classIdPair, String userId) { +// Session s = appSessionFactory.openSession(); +// try { +// Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); +// +// if (theClass != null) { +// IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); +// +// boolean hasAccess = (parent != null); +// +// if (hasAccess) { +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); +// if (mappedClass != null) { +// if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ +// Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); +// mappedClass.getReadQuery().setQueryParameters(readFilter, parent, userId); +// Number readFilterResult = (Number) readFilter.uniqueResult(); +// if (readFilterResult == null || readFilterResult.intValue() <= 0) +// hasAccess = false; +// } +// } +// } +// +// return hasAccess; +// } +// } catch (Exception e) { +// log.error("Unable to getReadAccess", e); +// } finally { +// s.close(); +// } +// return false; +// } +// +// @SuppressWarnings({ "rawtypes" }) +// public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { +// Session s = appSessionFactory.openSession(); +// try { +// Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); +// +// if (theClass != null) { +// IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); +// +// if (parent == null) +// return true; +// +// boolean hasAccess = true; +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); +// if (mappedClass != null) { +// if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ +// Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); +// mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, parent, userId); +// Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); +// if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) +// hasAccess = false; +// } +// } +// +// return hasAccess; +// } +// } catch (Exception e) { +// log.error("Unable to getDeleteAccess", e); +// } finally { +// s.close(); +// } +// return false; +// } +// +// @SuppressWarnings({ "rawtypes", "unchecked" }) +// public List findByIds(ClassIDPairs classIdPairs, String userId) { +// List result = null; +// +// boolean hasAccess = true; +// Class theClass = null; +// try { +// theClass = MappedClass.forName(classIdPairs.getClassName()); +// } catch (ClassNotFoundException e2) { +// log.error("Unable to get Class from class name " + classIdPairs.getClassName(), e2); +// return result; +// } +// +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPairs.getClassName()); +// boolean isValidReadQuery = false; +// if (mappedClass != null) { +// if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { +// isValidReadQuery = true; +// } +// +// } +// +// if (hasAccess) { +// if (theClass != null) { +// Set idsSet = new HashSet(classIdPairs.getIds().size()); +// idsSet.addAll(classIdPairs.getIds()); +// +// try { +// // Attempt to get as many from the cache as possible... +// Map cachedObjects = retrieveFromRedisCache(classIdPairs, true); +// +// if (!cachedObjects.isEmpty()) { +// result = new ArrayList(cachedObjects.size()); +// List cachedResults = new ArrayList(cachedObjects.size()); +// cachedResults.addAll(cachedObjects.values()); +// idsSet.removeAll(cachedObjects.keySet()); +// +// // If there is a read query, we need to check each object through that query. +// if (isValidReadQuery) { +// Session s = null; +// try { +// // Need to clean each result for the user. +// // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function +// s = appSessionFactory.openSession(); +// +// Iterator itrCachedResults = cachedResults.iterator(); +// while (itrCachedResults.hasNext()) { +// IPerceroObject nextCachedResult = itrCachedResults.next(); +// if (isValidReadQuery) { +// Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); +// mappedClass.getReadQuery().setQueryParameters(readFilter, nextCachedResult, userId); +// Number readFilterResult = (Number) readFilter.uniqueResult(); +// if (readFilterResult == null || readFilterResult.intValue() <= 0) +// hasAccess = false; +// } +// +// if (hasAccess) { +// result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); +// } +// } +// } catch (Exception e) { +// log.error("Error cleaning object for user in findByIds", e); +// } finally { +// if (s != null && s.isOpen()) { +// s.close(); +// } +// } +// } +// else { +// // This class has relationship objects that need to be cleaned. +// if (!mappedClass.getReadAccessRightsFieldReferences().isEmpty()) { +// Session s = null; +// try { +// // Need to clean each result for the user. +// // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function +// // TODO: Maybe only clean relationships that are in mappedClass.readAccessRightsFieldReferences? +// s = appSessionFactory.openSession(); +// +// Iterator itrCachedResults = cachedResults.iterator(); +// while (itrCachedResults.hasNext()) { +// IPerceroObject nextCachedResult = itrCachedResults.next(); +// result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); +// } +// } catch (Exception e) { +// log.error("Error cleaning object for user in findByIds", e); +// } finally { +// if (s != null && s.isOpen()) { +// s.close(); +// } +// } +// } +// else { +// // This class has NO read access query AND has NO relationships that require cleaning, +// // since this object is completely retrieved from redis, we can send as-is. +// // Though this may seem rare, this is probably a very common path. +// result.addAll(cachedResults); +// } +// } +// } +// } catch (Exception e1) { +// // We errored out here, but we can still try and retrieve from the database. +// log.error("Error retrieving objects from redis cache, attempting to retrieve from database", e1); +// } +// +// // Now get the rest from the database. +// if (!idsSet.isEmpty()) { +// String queryString = "SELECT findByIdsResult FROM " + classIdPairs.getClassName() + " findByIdsResult WHERE findByIdsResult.ID IN (:idsSet)"; +// +// // Open the database session. +// Session s = null; +// try { +// s = appSessionFactory.openSession(); +// Query query = null; +// +// // If the Read Query/Filter uses the ID, then we need to check against each ID here. +// if (isValidReadQuery) { +// String queryFilterString = mappedClass.getReadQuery().getQuery(); +// if (mappedClass.getReadQuery().getUseId()) { +// // Need to replace :id with +// queryFilterString = queryFilterString.replaceAll(":id", "findByIdsResult.ID"); +// queryFilterString = queryFilterString.replaceAll(":Id", "findByIdsResult.ID"); +// queryFilterString = queryFilterString.replaceAll(":iD", "findByIdsResult.ID"); +// queryFilterString = queryFilterString.replaceAll(":ID", "findByIdsResult.ID"); +// } +// queryFilterString = queryString + " AND (" + queryFilterString + ") > 0"; +// +// query = s.createQuery(queryFilterString); +// mappedClass.getReadQuery().setQueryParameters(query, null, userId); +// } +// else { +// query = s.createQuery(queryString); +// } +// +// query.setParameterList("idsSet", idsSet); +// List queryResult = query.list(); +// List cleanedDatabaseObjects = (List) SyncHibernateUtils.cleanObject(queryResult, s, userId); +// +// // Need to put results into cache. +// if (cacheTimeout > 0) { +// Map mapJsonObjectStrings = new HashMap(cleanedDatabaseObjects.size()); +// Iterator itrDatabaseObjects = cleanedDatabaseObjects.iterator(); +// while (itrDatabaseObjects.hasNext()) { +// IPerceroObject nextDatabaseObject = itrDatabaseObjects.next(); +// String nextCacheKey = RedisKeyUtils.classIdPair(nextDatabaseObject.getClass().getCanonicalName(), nextDatabaseObject.getID()); +// +// mapJsonObjectStrings.put(nextCacheKey, ((BaseDataObject)nextDatabaseObject).toJson()); +// } +// +// // Store the objects in redis. +// cacheDataStore.setValues(mapJsonObjectStrings); +// // (Re)Set the expiration. +// cacheDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); +// } +// +// if (result == null) { +// result = cleanedDatabaseObjects; +// } +// else { +// result.addAll(cleanedDatabaseObjects); +// } +// } catch (QueryException qe) { +// log.error("Unable to findByIds", qe); +// } catch (Exception e) { +// log.error("Unable to findByIds", e); +// } finally { +// if (s != null && s.isOpen()) { +// s.close(); +// } +// } +// } +// } +// } +// +// return result; +// } +// +// @SuppressWarnings({ "rawtypes", "unchecked" }) +// public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId) { +// Session s = appSessionFactory.openSession(); +// try { +// Class objectClass = theQueryObject.getClass(); +// +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(objectClass.getName()); +// if (mappedClass != null) { +// Iterator itr = mappedClass.uniqueConstraints.iterator(); +// while(itr.hasNext()) { +// Criteria criteria = null; +// Object nextConstraint = itr.next(); +// if (nextConstraint instanceof MappedField) { +// MappedField nextConstraintField = (MappedField) nextConstraint; +// Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); +// if (nextConstraintFieldValue != null) { +// if (criteria == null) +// criteria = s.createCriteria(objectClass); +// Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); +// criteria.add(uniqueFieldValue); +// } +// } +// else if (nextConstraint instanceof List) { +// List listMappedFields = (List) nextConstraint; +// Iterator itrMappedFields = listMappedFields.iterator(); +// while(itrMappedFields.hasNext()) { +// MappedField nextConstraintField = itrMappedFields.next(); +// Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); +// if (nextConstraintFieldValue != null) { +// if (criteria == null) +// criteria = s.createCriteria(objectClass); +// Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); +// criteria.add(uniqueFieldValue); +// } // } // } +// +// if (criteria != null) { +// criteria.setMaxResults(1); +// Object result = criteria.uniqueResult(); +// if (result != null) { +// // Make sure user has access. +// boolean hasAccess = true; +// if (mappedClass != null) { +// if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ +// Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); +// mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); +// Number readFilterResult = (Number) readFilter.uniqueResult(); +// if (readFilterResult == null || readFilterResult.intValue() <= 0) +// hasAccess = false; +// } +// } +// +// if (hasAccess) { +// result = SyncHibernateUtils.cleanObject(result, s, userId); +// return (IPerceroObject) result; +// } +// } +// } +// } +// } +// } catch (Exception e) { +// log.error("Unable to findByExample", e); +// } finally { +// s.close(); +// } +// +// return null; +// } +// +// // TODO: Add permissions check. +// @SuppressWarnings({ "unchecked" }) +// public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId) { +// Session s = appSessionFactory.openSession(); +// try { +// Criteria criteria = s.createCriteria(theQueryObject.getClass()); +// AssociationExample example = AssociationExample.create(theQueryObject); +// BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); +// example.setPropertySelector(propertySelector); +// criteria.add(example); +// +// List result = criteria.list(); +// result = (List) SyncHibernateUtils.cleanObject(result, s, userId); +// +// return (List) result; +// } catch (Exception e) { +// log.error("Unable to findByExample", e); +// } finally { +// s.close(); +// } +// +// return null; +// } +// +// @SuppressWarnings({ "unchecked" }) +// public List systemFindByExample(IPerceroObject theQueryObject, List excludeProperties) { +// Session s = appSessionFactory.openSession(); +// try { +// Criteria criteria = s.createCriteria(theQueryObject.getClass()); +// AssociationExample example = AssociationExample.create(theQueryObject); +// BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); +// example.setPropertySelector(propertySelector); +// criteria.add(example); +// +// List result = criteria.list(); +// result = (List) SyncHibernateUtils.cleanObject(result, s); +// +// return (List) result; +// } catch (Exception e) { +// log.error("Unable to findByExample", e); +// } finally { +// s.close(); +// } +// +// return null; +// } +// +// @SuppressWarnings("unchecked") +// public List searchByExample(IPerceroObject theQueryObject, +// List excludeProperties, String userId) { +// Session s = appSessionFactory.openSession(); +// try { +// Criteria criteria = s.createCriteria(theQueryObject.getClass()); +// AssociationExample example = AssociationExample.create(theQueryObject); +// BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); +// example.setPropertySelector(propertySelector); +// example.enableLike(MatchMode.ANYWHERE); +// criteria.add(example); +// +// List result = criteria.list(); +// result = (List) SyncHibernateUtils.cleanObject(result, s, userId); +// +// return result; +// } catch (Exception e) { +// log.error("Unable to searchByExample", e); +// } finally { +// s.close(); +// } +// +// return null; +// } +// +// @SuppressWarnings({ "unchecked", "rawtypes" }) +// public IPerceroObject systemCreateObject(IPerceroObject perceroObject) +// throws SyncException { +// Session s = appSessionFactory.openSession(); +// +// try { +// // Make sure object has an ID. +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); +// if (!mappedClass.hasGeneratedId && !StringUtils.hasText(perceroObject.getID())) +// perceroObject.setID(UUID.randomUUID().toString()); +// else { +// // Check to see if item already exists. +// Object existingObject = s.get(perceroObject.getClass(), perceroObject.getID()); +// if (existingObject != null) +// { +// perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(existingObject, s); +// deepCleanObject(perceroObject, mappedClass, s, null); +// return perceroObject; +// } +// } +// +// Transaction tx = s.beginTransaction(); +// tx.begin(); +// s.save(perceroObject); +// tx.commit(); +// +// s.refresh(perceroObject); +// +// perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObject, s); +// deepCleanObject(perceroObject, mappedClass, s, null); +// +// // Now update the cache. +// // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... +// if (cacheTimeout > 0) { +// String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); +// if (cacheTimeout > 0) { +// cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); +// cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); +// } +// +// Set keysToDelete = new HashSet(); +// MappedClass nextMappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); +// Iterator itrToManyFields = nextMappedClass.toManyFields.iterator(); +// while(itrToManyFields.hasNext()) { +// MappedField nextMappedField = itrToManyFields.next(); +// Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); +// if (fieldObject != null) { +// if (fieldObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); +// keysToDelete.add(nextKey); +// } +// else if (fieldObject instanceof Collection) { +// Iterator itrFieldObject = ((Collection) fieldObject).iterator(); +// while(itrFieldObject.hasNext()) { +// Object nextListObject = itrFieldObject.next(); +// if (nextListObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); +// keysToDelete.add(nextKey); +// } +// } +// } +// } +// } +// Iterator itrToOneFields = mappedClass.toOneFields.iterator(); +// while(itrToOneFields.hasNext()) { +// MappedField nextMappedField = itrToOneFields.next(); +// Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); +// if (fieldObject != null) { +// if (fieldObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); +// keysToDelete.add(nextKey); +// } +// else if (fieldObject instanceof Collection) { +// Iterator itrFieldObject = ((Collection) fieldObject).iterator(); +// while(itrFieldObject.hasNext()) { +// Object nextListObject = itrFieldObject.next(); +// if (nextListObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); +// keysToDelete.add(nextKey); +// } +// } +// } +// } +// } +// +// if (!keysToDelete.isEmpty()) { +// cacheDataStore.deleteKeys(keysToDelete); +// // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? +// //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); +// } +// } +// +// return perceroObject; +// } +// catch(PropertyValueException pve) { +// log.error("Error creating object", pve); +// +// SyncDataException sde = new SyncDataException(SyncDataException.MISSING_REQUIRED_FIELD, SyncDataException.MISSING_REQUIRED_FIELD_CODE, "Missing required field " + pve.getPropertyName()); +// sde.fieldName = pve.getPropertyName(); +// throw sde; +// } +// catch(Exception e) { +// log.error("Error creating object", e); +// +// SyncDataException sde = new SyncDataException(SyncDataException.CREATE_OBJECT_ERROR, SyncDataException.CREATE_OBJECT_ERROR_CODE); +// throw sde; +// } +// finally { +// if (s != null && s.isOpen()) { +// s.close(); +// } +// } +// } +// +// private void deepCleanObject(IPerceroObject perceroObject, MappedClass mappedClass, Session s, String userId) { +// if (!(perceroObject instanceof IRootObject)) { +// for(MappedField nextMappedField : mappedClass.externalizableFields) { +// try { +// if (nextMappedField instanceof MappedFieldPerceroObject) { +// Object fieldValue = nextMappedField.getValue(perceroObject); +// if (fieldValue != null) { +// fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); +// nextMappedField.getSetter().invoke(perceroObject, fieldValue); +// } +// } +// else if (nextMappedField instanceof MappedFieldList) { +// Object fieldValue = nextMappedField.getValue(perceroObject); +// if (fieldValue != null) { +// fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); +// nextMappedField.getSetter().invoke(perceroObject, fieldValue); +// } +// } +// else if (nextMappedField instanceof MappedFieldMap) { +// Object fieldValue = nextMappedField.getValue(perceroObject); +// if (fieldValue != null) { +// fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); +// nextMappedField.getSetter().invoke(perceroObject, fieldValue); +// } +// } +// } catch(Exception e) { +// log.error("Error in postCreateObject " + mappedClass.className + "." + nextMappedField.getField().getName(), e); +// } +// } +// } +// } +// +// public IPerceroObject createObject(IPerceroObject perceroObject, String userId) throws SyncException { +// boolean hasAccess = true; +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); +// if (mappedClass != null) { +// if (mappedClass.getCreateQuery() != null && StringUtils.hasText(mappedClass.getCreateQuery().getQuery())){ +// Session s = appSessionFactory.openSession(); +// try { +// Query createFilter = s.createQuery(mappedClass.getCreateQuery().getQuery()); +// mappedClass.getCreateQuery().setQueryParameters(createFilter, perceroObject, userId); +// Number createFilterResult = (Number) createFilter.uniqueResult(); +// if (createFilterResult == null || createFilterResult.intValue() <= 0) +// hasAccess = false; +// } catch (Exception e) { +// log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); +// hasAccess = false; +// } finally { +// s.close(); // } - } - - if (pleaseSetTimeout) { - cacheDataStore.expire(keys, cacheTimeout, TimeUnit.SECONDS); - } - } - - return result; - } - - @SuppressWarnings({ "rawtypes" }) - public Boolean getReadAccess(ClassIDPair classIdPair, String userId) { - Session s = appSessionFactory.openSession(); - try { - Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); - - if (theClass != null) { - IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); - - boolean hasAccess = (parent != null); - - if (hasAccess) { - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, parent, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - } - } - - return hasAccess; - } - } catch (Exception e) { - log.error("Unable to getReadAccess", e); - } finally { - s.close(); - } - return false; - } - - @SuppressWarnings({ "rawtypes" }) - public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { - Session s = appSessionFactory.openSession(); - try { - Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); - - if (theClass != null) { - IPerceroObject parent = (IPerceroObject) s.get(theClass, classIdPair.getID()); - - if (parent == null) - return true; - - boolean hasAccess = true; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); - if (mappedClass != null) { - if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ - Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); - mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, parent, userId); - Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); - if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) - hasAccess = false; - } - } - - return hasAccess; - } - } catch (Exception e) { - log.error("Unable to getDeleteAccess", e); - } finally { - s.close(); - } - return false; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public List findByIds(ClassIDPairs classIdPairs, String userId) { - List result = null; - - boolean hasAccess = true; - Class theClass = null; - try { - theClass = MappedClass.forName(classIdPairs.getClassName()); - } catch (ClassNotFoundException e2) { - log.error("Unable to get Class from class name " + classIdPairs.getClassName(), e2); - return result; - } - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPairs.getClassName()); - boolean isValidReadQuery = false; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - isValidReadQuery = true; - } - - } - - if (hasAccess) { - if (theClass != null) { - Set idsSet = new HashSet(classIdPairs.getIds().size()); - idsSet.addAll(classIdPairs.getIds()); - - try { - // Attempt to get as many from the cache as possible... - Map cachedObjects = retrieveFromRedisCache(classIdPairs, true); - - if (!cachedObjects.isEmpty()) { - result = new ArrayList(cachedObjects.size()); - List cachedResults = new ArrayList(cachedObjects.size()); - cachedResults.addAll(cachedObjects.values()); - idsSet.removeAll(cachedObjects.keySet()); - - // If there is a read query, we need to check each object through that query. - if (isValidReadQuery) { - Session s = null; - try { - // Need to clean each result for the user. - // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function - s = appSessionFactory.openSession(); - - Iterator itrCachedResults = cachedResults.iterator(); - while (itrCachedResults.hasNext()) { - IPerceroObject nextCachedResult = itrCachedResults.next(); - if (isValidReadQuery) { - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, nextCachedResult, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - - if (hasAccess) { - result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); - } - } - } catch (Exception e) { - log.error("Error cleaning object for user in findByIds", e); - } finally { - if (s != null && s.isOpen()) { - s.close(); - } - } - } - else { - // This class has relationship objects that need to be cleaned. - if (!mappedClass.getReadAccessRightsFieldReferences().isEmpty()) { - Session s = null; - try { - // Need to clean each result for the user. - // TODO: Need to figure out how to NOT open the Session if we don't have to. The problem lies in the SyncHibernateUtils.cleanObject function - // TODO: Maybe only clean relationships that are in mappedClass.readAccessRightsFieldReferences? - s = appSessionFactory.openSession(); - - Iterator itrCachedResults = cachedResults.iterator(); - while (itrCachedResults.hasNext()) { - IPerceroObject nextCachedResult = itrCachedResults.next(); - result.add( (IPerceroObject) SyncHibernateUtils.cleanObject(nextCachedResult, s, userId) ); - } - } catch (Exception e) { - log.error("Error cleaning object for user in findByIds", e); - } finally { - if (s != null && s.isOpen()) { - s.close(); - } - } - } - else { - // This class has NO read access query AND has NO relationships that require cleaning, - // since this object is completely retrieved from redis, we can send as-is. - // Though this may seem rare, this is probably a very common path. - result.addAll(cachedResults); - } - } - } - } catch (Exception e1) { - // We errored out here, but we can still try and retrieve from the database. - log.error("Error retrieving objects from redis cache, attempting to retrieve from database", e1); - } - - // Now get the rest from the database. - if (!idsSet.isEmpty()) { - String queryString = "SELECT findByIdsResult FROM " + classIdPairs.getClassName() + " findByIdsResult WHERE findByIdsResult.ID IN (:idsSet)"; - - // Open the database session. - Session s = null; - try { - s = appSessionFactory.openSession(); - Query query = null; - - // If the Read Query/Filter uses the ID, then we need to check against each ID here. - if (isValidReadQuery) { - String queryFilterString = mappedClass.getReadQuery().getQuery(); - if (mappedClass.getReadQuery().getUseId()) { - // Need to replace :id with - queryFilterString = queryFilterString.replaceAll(":id", "findByIdsResult.ID"); - queryFilterString = queryFilterString.replaceAll(":Id", "findByIdsResult.ID"); - queryFilterString = queryFilterString.replaceAll(":iD", "findByIdsResult.ID"); - queryFilterString = queryFilterString.replaceAll(":ID", "findByIdsResult.ID"); - } - queryFilterString = queryString + " AND (" + queryFilterString + ") > 0"; - - query = s.createQuery(queryFilterString); - mappedClass.getReadQuery().setQueryParameters(query, null, userId); - } - else { - query = s.createQuery(queryString); - } - - query.setParameterList("idsSet", idsSet); - List queryResult = query.list(); - List cleanedDatabaseObjects = (List) SyncHibernateUtils.cleanObject(queryResult, s, userId); - - // Need to put results into cache. - if (cacheTimeout > 0) { - Map mapJsonObjectStrings = new HashMap(cleanedDatabaseObjects.size()); - Iterator itrDatabaseObjects = cleanedDatabaseObjects.iterator(); - while (itrDatabaseObjects.hasNext()) { - IPerceroObject nextDatabaseObject = itrDatabaseObjects.next(); - String nextCacheKey = RedisKeyUtils.classIdPair(nextDatabaseObject.getClass().getCanonicalName(), nextDatabaseObject.getID()); - - mapJsonObjectStrings.put(nextCacheKey, ((BaseDataObject)nextDatabaseObject).toJson()); - } - - // Store the objects in redis. - cacheDataStore.setValues(mapJsonObjectStrings); - // (Re)Set the expiration. - cacheDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); - } - - if (result == null) { - result = cleanedDatabaseObjects; - } - else { - result.addAll(cleanedDatabaseObjects); - } - } catch (QueryException qe) { - log.error("Unable to findByIds", qe); - } catch (Exception e) { - log.error("Unable to findByIds", e); - } finally { - if (s != null && s.isOpen()) { - s.close(); - } - } - } - } - } - - return result; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId) { - Session s = appSessionFactory.openSession(); - try { - Class objectClass = theQueryObject.getClass(); - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(objectClass.getName()); - if (mappedClass != null) { - Iterator itr = mappedClass.uniqueConstraints.iterator(); - while(itr.hasNext()) { - Criteria criteria = null; - Object nextConstraint = itr.next(); - if (nextConstraint instanceof MappedField) { - MappedField nextConstraintField = (MappedField) nextConstraint; - Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); - if (nextConstraintFieldValue != null) { - if (criteria == null) - criteria = s.createCriteria(objectClass); - Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); - criteria.add(uniqueFieldValue); - } - } - else if (nextConstraint instanceof List) { - List listMappedFields = (List) nextConstraint; - Iterator itrMappedFields = listMappedFields.iterator(); - while(itrMappedFields.hasNext()) { - MappedField nextConstraintField = itrMappedFields.next(); - Object nextConstraintFieldValue = nextConstraintField.getValue(theQueryObject); - if (nextConstraintFieldValue != null) { - if (criteria == null) - criteria = s.createCriteria(objectClass); - Criterion uniqueFieldValue = Restrictions.eq(nextConstraintField.getField().getName(), nextConstraintFieldValue); - criteria.add(uniqueFieldValue); - } - } - } - - if (criteria != null) { - criteria.setMaxResults(1); - Object result = criteria.uniqueResult(); - if (result != null) { - // Make sure user has access. - boolean hasAccess = true; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - } - - if (hasAccess) { - result = SyncHibernateUtils.cleanObject(result, s, userId); - return (IPerceroObject) result; - } - } - } - } - } - } catch (Exception e) { - log.error("Unable to findByExample", e); - } finally { - s.close(); - } - - return null; - } - - // TODO: Add permissions check. - @SuppressWarnings({ "unchecked" }) - public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId) { - Session s = appSessionFactory.openSession(); - try { - Criteria criteria = s.createCriteria(theQueryObject.getClass()); - AssociationExample example = AssociationExample.create(theQueryObject); - BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); - example.setPropertySelector(propertySelector); - criteria.add(example); - - List result = criteria.list(); - result = (List) SyncHibernateUtils.cleanObject(result, s, userId); - - return (List) result; - } catch (Exception e) { - log.error("Unable to findByExample", e); - } finally { - s.close(); - } - - return null; - } - - @SuppressWarnings({ "unchecked" }) - public List systemFindByExample(IPerceroObject theQueryObject, List excludeProperties) { - Session s = appSessionFactory.openSession(); - try { - Criteria criteria = s.createCriteria(theQueryObject.getClass()); - AssociationExample example = AssociationExample.create(theQueryObject); - BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); - example.setPropertySelector(propertySelector); - criteria.add(example); - - List result = criteria.list(); - result = (List) SyncHibernateUtils.cleanObject(result, s); - - return (List) result; - } catch (Exception e) { - log.error("Unable to findByExample", e); - } finally { - s.close(); - } - - return null; - } - - @SuppressWarnings("unchecked") - public List searchByExample(IPerceroObject theQueryObject, - List excludeProperties, String userId) { - Session s = appSessionFactory.openSession(); - try { - Criteria criteria = s.createCriteria(theQueryObject.getClass()); - AssociationExample example = AssociationExample.create(theQueryObject); - BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(excludeProperties); - example.setPropertySelector(propertySelector); - example.enableLike(MatchMode.ANYWHERE); - criteria.add(example); - - List result = criteria.list(); - result = (List) SyncHibernateUtils.cleanObject(result, s, userId); - - return result; - } catch (Exception e) { - log.error("Unable to searchByExample", e); - } finally { - s.close(); - } - - return null; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public IPerceroObject systemCreateObject(IPerceroObject perceroObject) - throws SyncException { - Session s = appSessionFactory.openSession(); - - try { - // Make sure object has an ID. - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - if (!mappedClass.hasGeneratedId && !StringUtils.hasText(perceroObject.getID())) - perceroObject.setID(UUID.randomUUID().toString()); - else { - // Check to see if item already exists. - Object existingObject = s.get(perceroObject.getClass(), perceroObject.getID()); - if (existingObject != null) - { - perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(existingObject, s); - deepCleanObject(perceroObject, mappedClass, s, null); - return perceroObject; - } - } - - Transaction tx = s.beginTransaction(); - tx.begin(); - s.save(perceroObject); - tx.commit(); - - s.refresh(perceroObject); - - perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObject, s); - deepCleanObject(perceroObject, mappedClass, s, null); - - // Now update the cache. - // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... - if (cacheTimeout > 0) { - String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); - if (cacheTimeout > 0) { - cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); - cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); - } - - Set keysToDelete = new HashSet(); - MappedClass nextMappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - Iterator itrToManyFields = nextMappedClass.toManyFields.iterator(); - while(itrToManyFields.hasNext()) { - MappedField nextMappedField = itrToManyFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); - keysToDelete.add(nextKey); - } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); - keysToDelete.add(nextKey); - } - } - } - } - } - Iterator itrToOneFields = mappedClass.toOneFields.iterator(); - while(itrToOneFields.hasNext()) { - MappedField nextMappedField = itrToOneFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); - keysToDelete.add(nextKey); - } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); - keysToDelete.add(nextKey); - } - } - } - } - } - - if (!keysToDelete.isEmpty()) { - cacheDataStore.deleteKeys(keysToDelete); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - - return perceroObject; - } - catch(PropertyValueException pve) { - log.error("Error creating object", pve); - - SyncDataException sde = new SyncDataException(SyncDataException.MISSING_REQUIRED_FIELD, SyncDataException.MISSING_REQUIRED_FIELD_CODE, "Missing required field " + pve.getPropertyName()); - sde.fieldName = pve.getPropertyName(); - throw sde; - } - catch(Exception e) { - log.error("Error creating object", e); - - SyncDataException sde = new SyncDataException(SyncDataException.CREATE_OBJECT_ERROR, SyncDataException.CREATE_OBJECT_ERROR_CODE); - throw sde; - } - finally { - if (s != null && s.isOpen()) { - s.close(); - } - } - } - - private void deepCleanObject(IPerceroObject perceroObject, MappedClass mappedClass, Session s, String userId) { - if (!(perceroObject instanceof IRootObject)) { - for(MappedField nextMappedField : mappedClass.externalizableFields) { - try { - if (nextMappedField instanceof MappedFieldPerceroObject) { - Object fieldValue = nextMappedField.getValue(perceroObject); - if (fieldValue != null) { - fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); - nextMappedField.getSetter().invoke(perceroObject, fieldValue); - } - } - else if (nextMappedField instanceof MappedFieldList) { - Object fieldValue = nextMappedField.getValue(perceroObject); - if (fieldValue != null) { - fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); - nextMappedField.getSetter().invoke(perceroObject, fieldValue); - } - } - else if (nextMappedField instanceof MappedFieldMap) { - Object fieldValue = nextMappedField.getValue(perceroObject); - if (fieldValue != null) { - fieldValue = SyncHibernateUtils.cleanObject(fieldValue, s, userId); - nextMappedField.getSetter().invoke(perceroObject, fieldValue); - } - } - } catch(Exception e) { - log.error("Error in postCreateObject " + mappedClass.className + "." + nextMappedField.getField().getName(), e); - } - } - } - } - - public IPerceroObject createObject(IPerceroObject perceroObject, String userId) throws SyncException { - boolean hasAccess = true; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - if (mappedClass != null) { - if (mappedClass.getCreateQuery() != null && StringUtils.hasText(mappedClass.getCreateQuery().getQuery())){ - Session s = appSessionFactory.openSession(); - try { - Query createFilter = s.createQuery(mappedClass.getCreateQuery().getQuery()); - mappedClass.getCreateQuery().setQueryParameters(createFilter, perceroObject, userId); - Number createFilterResult = (Number) createFilter.uniqueResult(); - if (createFilterResult == null || createFilterResult.intValue() <= 0) - hasAccess = false; - } catch (Exception e) { - log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); - hasAccess = false; - } finally { - s.close(); - } - } - } - - if (hasAccess) { - return systemCreateObject(perceroObject); - } else { - return null; - } - } - - - - //////////////////////////////////////////////////// - // PUT - //////////////////////////////////////////////////// - public IPerceroObject putObject(IPerceroObject perceroObject, Map> changedFields, String userId) throws SyncException { - boolean hasAccess = true; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - if (mappedClass != null) { - if (mappedClass.getUpdateQuery() != null && StringUtils.hasText(mappedClass.getUpdateQuery().getQuery())){ - Session s = appSessionFactory.openSession(); - try { - Query updateFilter = s.createQuery(mappedClass.getUpdateQuery().getQuery()); - mappedClass.getUpdateQuery().setQueryParameters(updateFilter, perceroObject, userId); - Number updateFilterResult = (Number) updateFilter.uniqueResult(); - if (updateFilterResult == null || updateFilterResult.intValue() <= 0) - hasAccess = false; - } catch (Exception e) { - log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); - hasAccess = false; - } finally { - s.close(); - } - } - } - - if (hasAccess) { - return systemPutObject(perceroObject, changedFields); - } else { - return null; - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map> changedFields) throws SyncException { - Session s = null; - - try { - s = appSessionFactory.openSession(); - Transaction tx = s.beginTransaction(); - tx.begin(); - try { - //s.evict(perceroObject); - //perceroObject.setID(perceroObject.getID()); - perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObject, s); - //s.persist(perceroObject); - //perceroObject = (IPerceroObject) s.merge(perceroObject); - } catch(Exception e) { - e.printStackTrace(); - } - //s.saveOrUpdate(perceroObject); - s.update(perceroObject); - tx.commit(); - - s.refresh(perceroObject); - - ((BaseDataObject)perceroObject).setIsClean(false); - perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObject, s); - - // Now update the cache. - // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... - if (cacheTimeout > 0) { - // TODO: Also need to update the caches of anything object that is related to this object. - String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); - if (cacheDataStore.hasKey(key)) { - cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); - } - - // Iterate through each changed object and reset the cache for that object. - if (changedFields != null) { -// Iterator>> itrChangedFieldEntrySet = changedFields.entrySet().iterator(); +// } +// } +// +// if (hasAccess) { +// return systemCreateObject(perceroObject); +// } else { +// return null; +// } +// } +// +// +// +// //////////////////////////////////////////////////// +// // PUT +// //////////////////////////////////////////////////// +// public IPerceroObject putObject(IPerceroObject perceroObject, Map> changedFields, String userId) throws SyncException { +// boolean hasAccess = true; +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); +// if (mappedClass != null) { +// if (mappedClass.getUpdateQuery() != null && StringUtils.hasText(mappedClass.getUpdateQuery().getQuery())){ +// Session s = appSessionFactory.openSession(); +// try { +// Query updateFilter = s.createQuery(mappedClass.getUpdateQuery().getQuery()); +// mappedClass.getUpdateQuery().setQueryParameters(updateFilter, perceroObject, userId); +// Number updateFilterResult = (Number) updateFilter.uniqueResult(); +// if (updateFilterResult == null || updateFilterResult.intValue() <= 0) +// hasAccess = false; +// } catch (Exception e) { +// log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); +// hasAccess = false; +// } finally { +// s.close(); +// } +// } +// } +// +// if (hasAccess) { +// return systemPutObject(perceroObject, changedFields); +// } else { +// return null; +// } +// } +// +// @SuppressWarnings({ "unchecked", "rawtypes" }) +// public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map> changedFields) throws SyncException { +// Session s = null; +// +// try { +// s = appSessionFactory.openSession(); +// Transaction tx = s.beginTransaction(); +// tx.begin(); +// try { +// //s.evict(perceroObject); +// //perceroObject.setID(perceroObject.getID()); +// perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObject, s); +// //s.persist(perceroObject); +// //perceroObject = (IPerceroObject) s.merge(perceroObject); +// } catch(Exception e) { +// e.printStackTrace(); +// } +// //s.saveOrUpdate(perceroObject); +// s.update(perceroObject); +// tx.commit(); +// +// s.refresh(perceroObject); +// +// ((BaseDataObject)perceroObject).setIsClean(false); +// perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObject, s); +// +// // Now update the cache. +// // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... +// if (cacheTimeout > 0) { +// // TODO: Also need to update the caches of anything object that is related to this object. +// String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); +// if (cacheDataStore.hasKey(key)) { +// cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); +// } +// +// // Iterate through each changed object and reset the cache for that object. +// if (changedFields != null) { +//// Iterator>> itrChangedFieldEntrySet = changedFields.entrySet().iterator(); +//// Set keysToDelete = new HashSet(); +//// while (itrChangedFieldEntrySet.hasNext()) { +//// Map.Entry> nextEntry = itrChangedFieldEntrySet.next(); +//// ClassIDPair thePair = nextEntry.getKey(); +//// if (!thePair.comparePerceroObject(perceroObject)) { +//// String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); +//// keysToDelete.add(nextKey); +//// } +//// } +// Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); // Set keysToDelete = new HashSet(); -// while (itrChangedFieldEntrySet.hasNext()) { -// Map.Entry> nextEntry = itrChangedFieldEntrySet.next(); -// ClassIDPair thePair = nextEntry.getKey(); +// while (itrChangedFieldKeyset.hasNext()) { +// ClassIDPair thePair = itrChangedFieldKeyset.next(); // if (!thePair.comparePerceroObject(perceroObject)) { // String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); // keysToDelete.add(nextKey); // } // } - Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); - Set keysToDelete = new HashSet(); - while (itrChangedFieldKeyset.hasNext()) { - ClassIDPair thePair = itrChangedFieldKeyset.next(); - if (!thePair.comparePerceroObject(perceroObject)) { - String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); - keysToDelete.add(nextKey); - } - } - - if (!keysToDelete.isEmpty()) { - cacheDataStore.deleteKeys(keysToDelete); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - else { - // No changedFields? We should never get here? - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - Iterator itrToManyFields = mappedClass.toManyFields.iterator(); - while(itrToManyFields.hasNext()) { - MappedField nextMappedField = itrToManyFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); - if (cacheDataStore.hasKey(nextKey)) { - cacheDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); - if (cacheDataStore.hasKey(nextKey)) { - cacheDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - } - } - } - } - Iterator itrToOneFields = mappedClass.toOneFields.iterator(); - while(itrToOneFields.hasNext()) { - MappedField nextMappedField = itrToOneFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); - if (cacheDataStore.hasKey(nextKey)) { - cacheDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); - if (cacheDataStore.hasKey(nextKey)) { - cacheDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - } - } - } - } - } - } - - return perceroObject; - } catch (Exception e) { - log.error("Error putting object", e); - - SyncDataException sde = new SyncDataException(SyncDataException.UPDATE_OBJECT_ERROR, SyncDataException.UPDATE_OBJECT_ERROR_CODE); - throw sde; - } finally { - s.close(); - } - } - - - - //////////////////////////////////////////////////// - // DELETE - //////////////////////////////////////////////////// - public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws SyncException { - Session s = appSessionFactory.openSession(); - - try { - IPerceroObject perceroObject = (IPerceroObject) s.get(theClassIdPair.getClassName(), theClassIdPair.getID()); - if (perceroObject == null) { - return true; - } - - boolean hasAccess = true; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(theClassIdPair.getClassName()); - if (mappedClass != null) { - if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ - Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); - mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, perceroObject, userId); - Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); - if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) - hasAccess = false; - } - } - - if (hasAccess) { - if (systemDeleteObject(perceroObject)) { - return true; - } - else { - return true; - } - } else { - log.warn("No access to delete object " + theClassIdPair.toString()); - return false; - } - } catch (Exception e) { - log.error("Error putting object", e); - return false; - } finally { - s.close(); - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Boolean systemDeleteObject(IPerceroObject perceroObject) throws SyncException { - Boolean result = false; - Session s = appSessionFactory.openSession(); - - try { - // Load the object. - IPerceroObject perceroObjectToDelete = (IPerceroObject) s.load(perceroObject.getClass().getName(), perceroObject.getID()); - - // Make sure all associated objects are loaded. - // Clean the object before deletion because otherwise it will fail. - perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObjectToDelete, s); - - Transaction tx = s.beginTransaction(); - tx.begin(); - s.delete(perceroObjectToDelete); - tx.commit(); - - // Now delete from cache. - // Now update the cache. - // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... - if (cacheTimeout > 0) { - Set keysToDelete = new HashSet(); - - String key = RedisKeyUtils.classIdPair(SyncHibernateUtils.getShell(perceroObject).getClass().getCanonicalName(), perceroObject.getID()); - keysToDelete.add(key); - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(SyncHibernateUtils.getShell(perceroObject).getClass().getName()); - Iterator itrToManyFields = mappedClass.toManyFields.iterator(); - while(itrToManyFields.hasNext()) { - MappedField nextMappedField = itrToManyFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); - keysToDelete.add(nextKey); - } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); - keysToDelete.add(nextKey); - } - } - } - } - } - Iterator itrToOneFields = mappedClass.toOneFields.iterator(); - while(itrToOneFields.hasNext()) { - MappedField nextMappedField = itrToOneFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); - keysToDelete.add(nextKey); - } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); - keysToDelete.add(nextKey); - } - } - } - } - } - - if (!keysToDelete.isEmpty()) { - cacheDataStore.deleteKeys(keysToDelete); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - - result = true; - } catch (Exception e) { - log.error("Error deleting object", e); - - SyncDataException sde = new SyncDataException(SyncDataException.DELETE_OBJECT_ERROR, SyncDataException.DELETE_OBJECT_ERROR_CODE); - throw sde; - } finally { - s.close(); - } - - return result; - } - - /* - public Object cleanObject(Object object) { - return SyncHibernateUtils.cleanObject(object); - }*/ - - public Object cleanObject(Object object, Session s, String userId) { - try { - if (s == null) { - s = appSessionFactory.openSession(); - } - return SyncHibernateUtils.cleanObject(object, s, userId); - } catch(Exception e) { - log.warn("Error cleaning object", e); - return null; - } finally { - if (s != null && s.isOpen()) { - s.close(); - } - } - } - - - @SuppressWarnings("rawtypes") - public Map> getChangedMappedFields(IPerceroObject newObject) { - Map> result = new HashMap>(); - Collection baseObjectResult = null; - ClassIDPair basePair = new ClassIDPair(newObject.getID(), newObject.getClass().getCanonicalName()); - - String className = newObject.getClass().getCanonicalName(); - IPerceroObject oldObject = systemGetById(new ClassIDPair(newObject.getID(), className)); - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mc = mcm.getMappedClassByClassName(className); - Iterator itrMappedFields = mc.externalizableFields.iterator(); - while (itrMappedFields.hasNext()) { - MappedField nextMappedField = itrMappedFields.next(); - try { - Boolean fieldIsEqual = nextMappedField.compareObjects(oldObject, newObject); - if (!fieldIsEqual) { - if (baseObjectResult == null) { - baseObjectResult = new HashSet(); - result.put(basePair, baseObjectResult); - } - baseObjectResult.add(nextMappedField); - - // If this is a relationship field, then need to grab the old and new values. - if (nextMappedField.getReverseMappedField() != null) { - if (nextMappedField instanceof MappedFieldPerceroObject) { - MappedFieldPerceroObject nextMappedFieldPerceroObject = (MappedFieldPerceroObject) nextMappedField; - - IPerceroObject oldReversePerceroObject = (IPerceroObject) nextMappedFieldPerceroObject.getGetter().invoke(oldObject); - if (oldReversePerceroObject != null) { - ClassIDPair oldReversePair = new ClassIDPair(oldReversePerceroObject.getID(), oldReversePerceroObject.getClass().getCanonicalName()); - Collection oldReverseChangedFields = result.get(oldReversePair); - if (oldReverseChangedFields == null) { - oldReverseChangedFields = new HashSet(); - result.put(oldReversePair, oldReverseChangedFields); - } - oldReverseChangedFields.add(nextMappedField.getReverseMappedField()); - } - - IPerceroObject newReversePerceroObject = (IPerceroObject) nextMappedFieldPerceroObject.getGetter().invoke(newObject); - if (newReversePerceroObject != null) { - ClassIDPair newReversePair = new ClassIDPair(newReversePerceroObject.getID(), newReversePerceroObject.getClass().getCanonicalName()); - Collection changedFields = result.get(newReversePair); - if (changedFields == null) { - changedFields = new HashSet(); - result.put(newReversePair, changedFields); - } - changedFields.add(nextMappedField.getReverseMappedField()); - } - } - else if (nextMappedField instanceof MappedFieldList) { - MappedFieldList nextMappedFieldList = (MappedFieldList) nextMappedField; - - List oldReverseList = (List) nextMappedFieldList.getGetter().invoke(oldObject); - if (oldReverseList == null) - oldReverseList = new ArrayList(); - - List newReverseList = (List) nextMappedFieldList.getGetter().invoke(newObject); - if (newReverseList == null) - newReverseList = new ArrayList(); - - // Compare each item in the lists. - Collection oldChangedList = retrieveObjectsNotInCollection(oldReverseList, newReverseList); - Iterator itrOldChangedList = oldChangedList.iterator(); - while (itrOldChangedList.hasNext()) { - BaseDataObject nextOldChangedObject = (BaseDataObject) itrOldChangedList.next(); - ClassIDPair nextOldReversePair = BaseDataObject.toClassIdPair(nextOldChangedObject); - - // Old object is not in new list, so add to list of changed fields. - Collection changedFields = result.get(nextOldReversePair); - if (changedFields == null) { - changedFields = new HashSet(); - result.put(nextOldReversePair, changedFields); - } - changedFields.add(nextMappedField.getReverseMappedField()); - } - - Collection newChangedList = retrieveObjectsNotInCollection(newReverseList, oldReverseList); - Iterator itrNewChangedList = newChangedList.iterator(); - while (itrNewChangedList.hasNext()) { - BaseDataObject nextNewChangedObject = (BaseDataObject) itrNewChangedList.next(); - ClassIDPair nextNewReversePair = BaseDataObject.toClassIdPair(nextNewChangedObject); - - // Old object is not in new list, so add to list of changed fields. - Collection changedFields = result.get(nextNewReversePair); - if (changedFields == null) { - changedFields = new HashSet(); - result.put(nextNewReversePair, changedFields); - } - changedFields.add(nextMappedField.getReverseMappedField()); - } - } - } - } - } catch(Exception e) { - log.warn("Error getting changed field: " + nextMappedField.getField().getName(), e); - baseObjectResult.add(nextMappedField); - } - } - - return result; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private Collection retrieveObjectsNotInCollection(Collection baseList, Collection compareToList) { - Collection result = new HashSet(); - Iterator itrBaseList = baseList.iterator(); - Iterator itrCompareToList = null; - boolean matchFound = false; - - while (itrBaseList.hasNext()) { - BaseDataObject nextBasePerceroObject = (BaseDataObject) itrBaseList.next(); - ClassIDPair nextBasePair = BaseDataObject.toClassIdPair(nextBasePerceroObject); - nextBasePerceroObject = (BaseDataObject) systemGetById(nextBasePair); - - itrCompareToList = compareToList.iterator(); - matchFound = false; - while (itrCompareToList.hasNext()) { - BaseDataObject nextCompareToPerceroObject = (BaseDataObject) itrCompareToList.next(); - nextCompareToPerceroObject = (BaseDataObject) systemGetById(BaseDataObject.toClassIdPair(nextCompareToPerceroObject)); - - if (nextBasePerceroObject.getClass() == nextCompareToPerceroObject.getClass() && nextBasePerceroObject.getID().equalsIgnoreCase(nextCompareToPerceroObject.getID())) { - matchFound = true; - break; - } - } - - if (!matchFound) { - result.add(nextBasePerceroObject); - } - } - - return result; - } -} +// +// if (!keysToDelete.isEmpty()) { +// cacheDataStore.deleteKeys(keysToDelete); +// // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? +// //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); +// } +// } +// else { +// // No changedFields? We should never get here? +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); +// Iterator itrToManyFields = mappedClass.toManyFields.iterator(); +// while(itrToManyFields.hasNext()) { +// MappedField nextMappedField = itrToManyFields.next(); +// Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); +// if (fieldObject != null) { +// if (fieldObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); +// if (cacheDataStore.hasKey(nextKey)) { +// cacheDataStore.deleteKey(nextKey); +// // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? +// //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); +// } +// } +// else if (fieldObject instanceof Collection) { +// Iterator itrFieldObject = ((Collection) fieldObject).iterator(); +// while(itrFieldObject.hasNext()) { +// Object nextListObject = itrFieldObject.next(); +// if (nextListObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); +// if (cacheDataStore.hasKey(nextKey)) { +// cacheDataStore.deleteKey(nextKey); +// // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? +// //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); +// } +// } +// } +// } +// } +// } +// Iterator itrToOneFields = mappedClass.toOneFields.iterator(); +// while(itrToOneFields.hasNext()) { +// MappedField nextMappedField = itrToOneFields.next(); +// Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); +// if (fieldObject != null) { +// if (fieldObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); +// if (cacheDataStore.hasKey(nextKey)) { +// cacheDataStore.deleteKey(nextKey); +// // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? +// //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); +// } +// } +// else if (fieldObject instanceof Collection) { +// Iterator itrFieldObject = ((Collection) fieldObject).iterator(); +// while(itrFieldObject.hasNext()) { +// Object nextListObject = itrFieldObject.next(); +// if (nextListObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); +// if (cacheDataStore.hasKey(nextKey)) { +// cacheDataStore.deleteKey(nextKey); +// // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? +// //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); +// } +// } +// } +// } +// } +// } +// } +// } +// +// return perceroObject; +// } catch (Exception e) { +// log.error("Error putting object", e); +// +// SyncDataException sde = new SyncDataException(SyncDataException.UPDATE_OBJECT_ERROR, SyncDataException.UPDATE_OBJECT_ERROR_CODE); +// throw sde; +// } finally { +// s.close(); +// } +// } +// +// +// +// //////////////////////////////////////////////////// +// // DELETE +// //////////////////////////////////////////////////// +// public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws SyncException { +// Session s = appSessionFactory.openSession(); +// +// try { +// IPerceroObject perceroObject = (IPerceroObject) s.get(theClassIdPair.getClassName(), theClassIdPair.getID()); +// if (perceroObject == null) { +// return true; +// } +// +// boolean hasAccess = true; +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(theClassIdPair.getClassName()); +// if (mappedClass != null) { +// if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ +// Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); +// mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, perceroObject, userId); +// Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); +// if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) +// hasAccess = false; +// } +// } +// +// if (hasAccess) { +// if (systemDeleteObject(perceroObject)) { +// return true; +// } +// else { +// return true; +// } +// } else { +// log.warn("No access to delete object " + theClassIdPair.toString()); +// return false; +// } +// } catch (Exception e) { +// log.error("Error putting object", e); +// return false; +// } finally { +// s.close(); +// } +// } +// +// @SuppressWarnings({ "unchecked", "rawtypes" }) +// public Boolean systemDeleteObject(IPerceroObject perceroObject) throws SyncException { +// Boolean result = false; +// Session s = appSessionFactory.openSession(); +// +// try { +// // Load the object. +// IPerceroObject perceroObjectToDelete = (IPerceroObject) s.load(perceroObject.getClass().getName(), perceroObject.getID()); +// +// // Make sure all associated objects are loaded. +// // Clean the object before deletion because otherwise it will fail. +// perceroObject = (IPerceroObject) SyncHibernateUtils.cleanObject(perceroObjectToDelete, s); +// +// Transaction tx = s.beginTransaction(); +// tx.begin(); +// s.delete(perceroObjectToDelete); +// tx.commit(); +// +// // Now delete from cache. +// // Now update the cache. +// // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... +// if (cacheTimeout > 0) { +// Set keysToDelete = new HashSet(); +// +// String key = RedisKeyUtils.classIdPair(SyncHibernateUtils.getShell(perceroObject).getClass().getCanonicalName(), perceroObject.getID()); +// keysToDelete.add(key); +// +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mappedClass = mcm.getMappedClassByClassName(SyncHibernateUtils.getShell(perceroObject).getClass().getName()); +// Iterator itrToManyFields = mappedClass.toManyFields.iterator(); +// while(itrToManyFields.hasNext()) { +// MappedField nextMappedField = itrToManyFields.next(); +// Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); +// if (fieldObject != null) { +// if (fieldObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); +// keysToDelete.add(nextKey); +// } +// else if (fieldObject instanceof Collection) { +// Iterator itrFieldObject = ((Collection) fieldObject).iterator(); +// while(itrFieldObject.hasNext()) { +// Object nextListObject = itrFieldObject.next(); +// if (nextListObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); +// keysToDelete.add(nextKey); +// } +// } +// } +// } +// } +// Iterator itrToOneFields = mappedClass.toOneFields.iterator(); +// while(itrToOneFields.hasNext()) { +// MappedField nextMappedField = itrToOneFields.next(); +// Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); +// if (fieldObject != null) { +// if (fieldObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); +// keysToDelete.add(nextKey); +// } +// else if (fieldObject instanceof Collection) { +// Iterator itrFieldObject = ((Collection) fieldObject).iterator(); +// while(itrFieldObject.hasNext()) { +// Object nextListObject = itrFieldObject.next(); +// if (nextListObject instanceof IPerceroObject) { +// String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); +// keysToDelete.add(nextKey); +// } +// } +// } +// } +// } +// +// if (!keysToDelete.isEmpty()) { +// cacheDataStore.deleteKeys(keysToDelete); +// // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? +// //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); +// } +// } +// +// result = true; +// } catch (Exception e) { +// log.error("Error deleting object", e); +// +// SyncDataException sde = new SyncDataException(SyncDataException.DELETE_OBJECT_ERROR, SyncDataException.DELETE_OBJECT_ERROR_CODE); +// throw sde; +// } finally { +// s.close(); +// } +// +// return result; +// } +// +// /* +// public Object cleanObject(Object object) { +// return SyncHibernateUtils.cleanObject(object); +// }*/ +// +// public Object cleanObject(Object object, Session s, String userId) { +// try { +// if (s == null) { +// s = appSessionFactory.openSession(); +// } +// return SyncHibernateUtils.cleanObject(object, s, userId); +// } catch(Exception e) { +// log.warn("Error cleaning object", e); +// return null; +// } finally { +// if (s != null && s.isOpen()) { +// s.close(); +// } +// } +// } +// +// +// @SuppressWarnings("rawtypes") +// public Map> getChangedMappedFields(IPerceroObject newObject) { +// Map> result = new HashMap>(); +// Collection baseObjectResult = null; +// ClassIDPair basePair = new ClassIDPair(newObject.getID(), newObject.getClass().getCanonicalName()); +// +// String className = newObject.getClass().getCanonicalName(); +// IPerceroObject oldObject = systemGetById(new ClassIDPair(newObject.getID(), className)); +// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); +// MappedClass mc = mcm.getMappedClassByClassName(className); +// Iterator itrMappedFields = mc.externalizableFields.iterator(); +// while (itrMappedFields.hasNext()) { +// MappedField nextMappedField = itrMappedFields.next(); +// try { +// Boolean fieldIsEqual = nextMappedField.compareObjects(oldObject, newObject); +// if (!fieldIsEqual) { +// if (baseObjectResult == null) { +// baseObjectResult = new HashSet(); +// result.put(basePair, baseObjectResult); +// } +// baseObjectResult.add(nextMappedField); +// +// // If this is a relationship field, then need to grab the old and new values. +// if (nextMappedField.getReverseMappedField() != null) { +// if (nextMappedField instanceof MappedFieldPerceroObject) { +// MappedFieldPerceroObject nextMappedFieldPerceroObject = (MappedFieldPerceroObject) nextMappedField; +// +// IPerceroObject oldReversePerceroObject = (IPerceroObject) nextMappedFieldPerceroObject.getGetter().invoke(oldObject); +// if (oldReversePerceroObject != null) { +// ClassIDPair oldReversePair = new ClassIDPair(oldReversePerceroObject.getID(), oldReversePerceroObject.getClass().getCanonicalName()); +// Collection oldReverseChangedFields = result.get(oldReversePair); +// if (oldReverseChangedFields == null) { +// oldReverseChangedFields = new HashSet(); +// result.put(oldReversePair, oldReverseChangedFields); +// } +// oldReverseChangedFields.add(nextMappedField.getReverseMappedField()); +// } +// +// IPerceroObject newReversePerceroObject = (IPerceroObject) nextMappedFieldPerceroObject.getGetter().invoke(newObject); +// if (newReversePerceroObject != null) { +// ClassIDPair newReversePair = new ClassIDPair(newReversePerceroObject.getID(), newReversePerceroObject.getClass().getCanonicalName()); +// Collection changedFields = result.get(newReversePair); +// if (changedFields == null) { +// changedFields = new HashSet(); +// result.put(newReversePair, changedFields); +// } +// changedFields.add(nextMappedField.getReverseMappedField()); +// } +// } +// else if (nextMappedField instanceof MappedFieldList) { +// MappedFieldList nextMappedFieldList = (MappedFieldList) nextMappedField; +// +// List oldReverseList = (List) nextMappedFieldList.getGetter().invoke(oldObject); +// if (oldReverseList == null) +// oldReverseList = new ArrayList(); +// +// List newReverseList = (List) nextMappedFieldList.getGetter().invoke(newObject); +// if (newReverseList == null) +// newReverseList = new ArrayList(); +// +// // Compare each item in the lists. +// Collection oldChangedList = retrieveObjectsNotInCollection(oldReverseList, newReverseList); +// Iterator itrOldChangedList = oldChangedList.iterator(); +// while (itrOldChangedList.hasNext()) { +// BaseDataObject nextOldChangedObject = (BaseDataObject) itrOldChangedList.next(); +// ClassIDPair nextOldReversePair = BaseDataObject.toClassIdPair(nextOldChangedObject); +// +// // Old object is not in new list, so add to list of changed fields. +// Collection changedFields = result.get(nextOldReversePair); +// if (changedFields == null) { +// changedFields = new HashSet(); +// result.put(nextOldReversePair, changedFields); +// } +// changedFields.add(nextMappedField.getReverseMappedField()); +// } +// +// Collection newChangedList = retrieveObjectsNotInCollection(newReverseList, oldReverseList); +// Iterator itrNewChangedList = newChangedList.iterator(); +// while (itrNewChangedList.hasNext()) { +// BaseDataObject nextNewChangedObject = (BaseDataObject) itrNewChangedList.next(); +// ClassIDPair nextNewReversePair = BaseDataObject.toClassIdPair(nextNewChangedObject); +// +// // Old object is not in new list, so add to list of changed fields. +// Collection changedFields = result.get(nextNewReversePair); +// if (changedFields == null) { +// changedFields = new HashSet(); +// result.put(nextNewReversePair, changedFields); +// } +// changedFields.add(nextMappedField.getReverseMappedField()); +// } +// } +// } +// } +// } catch(Exception e) { +// log.warn("Error getting changed field: " + nextMappedField.getField().getName(), e); +// baseObjectResult.add(nextMappedField); +// } +// } +// +// return result; +// } +// +// @SuppressWarnings({ "rawtypes", "unchecked" }) +// private Collection retrieveObjectsNotInCollection(Collection baseList, Collection compareToList) { +// Collection result = new HashSet(); +// Iterator itrBaseList = baseList.iterator(); +// Iterator itrCompareToList = null; +// boolean matchFound = false; +// +// while (itrBaseList.hasNext()) { +// BaseDataObject nextBasePerceroObject = (BaseDataObject) itrBaseList.next(); +// ClassIDPair nextBasePair = BaseDataObject.toClassIdPair(nextBasePerceroObject); +// nextBasePerceroObject = (BaseDataObject) systemGetById(nextBasePair); +// +// itrCompareToList = compareToList.iterator(); +// matchFound = false; +// while (itrCompareToList.hasNext()) { +// BaseDataObject nextCompareToPerceroObject = (BaseDataObject) itrCompareToList.next(); +// nextCompareToPerceroObject = (BaseDataObject) systemGetById(BaseDataObject.toClassIdPair(nextCompareToPerceroObject)); +// +// if (nextBasePerceroObject.getClass() == nextCompareToPerceroObject.getClass() && nextBasePerceroObject.getID().equalsIgnoreCase(nextCompareToPerceroObject.getID())) { +// matchFound = true; +// break; +// } +// } +// +// if (!matchFound) { +// result.add(nextBasePerceroObject); +// } +// } +// +// return result; +// } +//} diff --git a/src/main/java/com/percero/agents/sync/services/IDataProvider.java b/src/main/java/com/percero/agents/sync/services/IDataProvider.java index 49178ec..8130122 100644 --- a/src/main/java/com/percero/agents/sync/services/IDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/IDataProvider.java @@ -4,8 +4,6 @@ import java.util.List; import java.util.Map; -import org.hibernate.Session; - import com.percero.agents.sync.exceptions.SyncException; import com.percero.agents.sync.metadata.MappedClass; import com.percero.agents.sync.metadata.MappedField; @@ -21,27 +19,27 @@ public interface IDataProvider { public String getName(); public Integer countAllByName(String className, String userId) throws Exception; - public PerceroList getAllByName(Object aName, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception; - public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String clientId); + public PerceroList getAllByName(String className, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception; + public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String clientId) throws SyncException; public IPerceroObject findById(ClassIDPair classIdPair, String userId); - public T systemGetById(ClassIDPair classIdPair); +// public T systemGetById(ClassIDPair classIdPair); public List findByIds(ClassIDPairs classIdPairs, String userId); - public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId); - public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId); - public List systemFindByExample(IPerceroObject theQueryObject, List excludeProperties); - public List searchByExample(IPerceroObject theQueryObject, List excludeProperties, String userId); +// public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId); + public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId, Boolean shellOnly) throws SyncException; +// public List systemFindByExample(IPerceroObject theQueryObject, List excludeProperties); +// public List searchByExample(IPerceroObject theQueryObject, List excludeProperties, String userId); public Boolean getReadAccess(ClassIDPair classIdPair, String userId); public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId); - public T systemCreateObject(IPerceroObject perceroObject) throws SyncException; - public IPerceroObject createObject(IPerceroObject perceroObject, String userId) throws SyncException; - public IPerceroObject putObject(IPerceroObject perceroObject, Map> changedFields, String userId) throws SyncException; - public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map> changedFields) throws SyncException; +// public T systemCreateObject(IPerceroObject perceroObject) throws SyncException; + public T createObject(T perceroObject, String userId) throws SyncException; + public T putObject(T perceroObject, Map> changedFields, String userId) throws SyncException; +// public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map> changedFields) throws SyncException; public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws SyncException; - public Boolean systemDeleteObject(IPerceroObject perceroObject) throws SyncException; +// public Boolean systemDeleteObject(IPerceroObject perceroObject) throws SyncException; //public Object cleanObject(Object object, String userId); - public Object cleanObject(Object object, Session s, String userId); +// public Object cleanObject(Object object, Session s, String userId); /** * Returns a map of changed fields for the base IPerceroObject as well as all associated objects that will @@ -67,4 +65,10 @@ public interface IDataProvider { public List findAllRelatedObjects(IPerceroObject perceroObject, MappedField mappedField, Boolean shellOnly, String userId) throws SyncException; public List getAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException; + + IPerceroObject cleanObject(IPerceroObject perceroObject, String userId) + throws SyncException; + + List cleanObject(List perceroObjects, + String userId) throws SyncException; } diff --git a/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java b/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java index edb4ed9..e743e77 100644 --- a/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java +++ b/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java @@ -24,7 +24,7 @@ public interface ISyncAgentService { public ServerResponse createObject(IPerceroObject perceroObject, String clientId) throws Exception; public ServerResponse createObject(IPerceroObject perceroObject, String clientId, Boolean pushToClient) throws Exception; - public T systemCreateObject(IPerceroObject perceroObject, String userId) throws SyncException; + public T systemCreateObject(T perceroObject, String userId) throws SyncException; public ServerResponse deleteObject(ClassIDPair theClassIdPair, String clientId) throws Exception; public ServerResponse deleteObject(ClassIDPair theClassIdPair, String clientId, Boolean pushToClient) throws Exception; public ServerResponse deleteObjectById(String theClassName, String theId, String clientId) throws Exception; @@ -39,21 +39,21 @@ public interface ISyncAgentService { public ServerResponse processTransaction(List objectsToSave, List objectsToRemove, String transactionId, Date transDate, String clientId) throws Exception; public Map countAllByName(Collection classNames, String clientId) throws Exception; - public PerceroList getAllByName(Object aName, Boolean returnTotal, String clientId) throws Exception; - public PerceroList getAllByName(Object aName, Integer pageNumber, Integer pageSize, Boolean returnTotal, String clientId) throws Exception; + public PerceroList getAllByName(String className, Boolean returnTotal, String clientId) throws Exception; + public PerceroList getAllByName(String className, Integer pageNumber, Integer pageSize, Boolean returnTotal, String clientId) throws Exception; public Object findById(ClassIDPair classIdPair, String clientId) throws Exception; public Object findById(String aClassName, String anId, String clientId) throws Exception; - public T systemGetByObject(IPerceroObject perceroObject); + public T systemGetByObject(T perceroObject); public IPerceroObject systemGetById(ClassIDPair cip); public IPerceroObject systemGetById(String aClassName, String anId); - public List systemFindByExample(Object theQueryObject, List excludeProperties); + public List systemFindByExample(Object theQueryObject, List excludeProperties) throws SyncException; public List findByIds(List classIdList, String clientId) throws Exception; public Object findByExample(Object theQueryObject, List excludeProperties, String clientId) throws Exception; public Object findUnique(Object theQueryObject, String clientId) throws Exception; public Object runQuery(String className, String queryName, Object[] queryArguments, String clientId) throws Exception; public Object runProcess(String processName, Object[] queryArguments, String clientId) throws Exception; public Object getChangeWatcherValue(ClassIDPair classIdPair, String fieldName, String[] params, String clientId) throws Exception; - public List getHistory(String aClassName, String anId, String clientId) throws Exception; + public List getHistory(String aClassName, String anId, String clientId) throws Exception; public Object searchByExample(Object theQueryObject, String clientId) throws Exception; public Object searchByExample(Object theQueryObject, List excludeProperties, String clientId) throws Exception; diff --git a/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java b/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java deleted file mode 100644 index de3cbaa..0000000 --- a/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java +++ /dev/null @@ -1,362 +0,0 @@ -package com.percero.agents.sync.services; - -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.hibernate.Session; -import org.springframework.stereotype.Component; - -import com.percero.agents.sync.metadata.MappedClass; -import com.percero.agents.sync.metadata.MappedField; -import com.percero.agents.sync.vo.ClassIDPair; -import com.percero.agents.sync.vo.ClassIDPairs; -import com.percero.framework.vo.IPerceroObject; -import com.percero.framework.vo.PerceroList; - -@Component -public class RedisDataProvider implements IDataProvider { - - //private static final Logger log = Logger.getLogger(RedisDataProvider.class); - - public void initialize() - { - // Do nothing. - } - - public String getName() { - return "redis"; - } - - - public Integer countAllByName(String className, String userId) throws Exception { - return null; - } - - public PerceroList getAllByName(Object aName, Integer pageNumber, Integer pageSize, Boolean returnTotal, String clientId) throws Exception { -/* try { - String aClassName = aName.toString(); - Query query = null; - Class theClass = Class.forName(aName.toString()); - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); - boolean isValidReadQuery = false; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - isValidReadQuery = true; - } - } - - if (theClass != null) { - Set resultSet = (Set) JOhm.getAll(theClass); - List result = new ArrayList(resultSet); - return result; - /** - String queryString = "SELECT getAllResult FROM " + aClassName + " getAllResult"; - - // If the Read Query/Filter uses the ID, then we need to check against each ID here. - if (isValidReadQuery) { - String queryFilterString = mappedClass.getReadQuery().getQuery(); - if (mappedClass.getReadQuery().getUseId()) { - // Need to replace :id with - queryFilterString = queryFilterString.replaceAll(":id", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":Id", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":iD", "getAllResult.ID"); - queryFilterString = queryFilterString.replaceAll(":ID", "getAllResult.ID"); - } - queryFilterString = queryString + " WHERE (" + queryFilterString + ") > 0"; - - query = s.createQuery(queryFilterString); - mappedClass.getReadQuery().setQueryParameters(query, null, client.getBelongsToUserId()); - } - else { - queryString += " ORDER BY ID"; - query = s.createQuery(queryString); - if (pageSize != null && pageNumber != null && pageSize.intValue() > 0) { - int pageValue = pageSize.intValue() * pageNumber.intValue(); - query.setFirstResult(pageValue); - query.setMaxResults(pageSize.intValue()); - //queryString += " LIMIT " + pageValue + " " + pageSize.toString(); - } - } - ** - }*/ - - /** - if (query != null) { - List result = (List) query.list(); - result = (List) HibernateUtils.cleanObject(result); - - return result; - } - else { - return null; - }** - - } catch (Exception e) { - log.error("Unable to getAllByName", e); - }*/ - - return null; - } - - public Boolean getReadAccess(ClassIDPair classIdPair, String userId) { - return null; - } - - public IPerceroObject findById(ClassIDPair classIdPair, String userId) { -/* try { - Class theClass = Class.forName(classIdPair.getClassName().toString()); - return (IPerceroObject) JOhm.get(theClass, classIdPair.getID()); - } catch (Exception e) { - log.error("Unable to findById", e); - }*/ - return null; -/** Session s = appSessionFactory.openSession(); - try { - Class theClass = Class.forName(classIdPair.getClassName().toString()); - - if (theClass != null) { - IPerceroObject result = (IPerceroObject) s.get(theClass, classIdPair.getID()); - - boolean hasAccess = (result != null); - - if (hasAccess) { - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, result, client.getBelongsToUserId()); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - } - } - - if (hasAccess) { - result = (IPerceroObject) HibernateUtils.cleanObject(result); - return result; - - } else - return null; - } else { - return null; - } - } catch (Exception e) { - log.error("Unable to findById", e); - } finally { - s.close(); - } - return null;**/ - } - - public IPerceroObject systemGetById(ClassIDPair classIdPair) { - return null; - } - - public List findByIds(ClassIDPairs classIdPairs, String clientId) { -/* List result = null; - - try { - Class theClass = Class.forName(classIdPairs.getClassName().toString()); - for(String nextId : classIdPairs.getIds()) { - IPerceroObject nextObject = JOhm.get(theClass, nextId); - if (nextObject != null) - result.add(nextObject); - } - return result; - } catch (Exception e) { - log.error("Unable to findById", e); - }*/ - return null; - - /** - Session s = appSessionFactory.openSession(); - - try { - boolean hasAccess = true; - Query query = null; - Class theClass = Class.forName(classIdPairs.getClassName().toString()); - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPairs.getClassName()); - boolean isValidReadQuery = false; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - isValidReadQuery = true; - } - - } - - if (hasAccess) { - if (theClass != null) - { - String strIds = ""; - int count = 0; - for(String nextId : classIdPairs.getIds()) { - if (count > 0) - strIds += ","; - strIds += "'" + nextId + "'"; - count++; - } - - String queryString = "SELECT findByIdsResult FROM " + classIdPairs.getClassName() + " findByIdsResult WHERE findByIdsResult.ID IN (" + strIds + ")"; - - // If the Read Query/Filter uses the ID, then we need to check against each ID here. - if (isValidReadQuery) { - String queryFilterString = mappedClass.getReadQuery().getQuery(); - if (mappedClass.getReadQuery().getUseId()) { - // Need to replace :id with - queryFilterString = queryFilterString.replaceAll(":id", "findByIdsResult.ID"); - queryFilterString = queryFilterString.replaceAll(":Id", "findByIdsResult.ID"); - queryFilterString = queryFilterString.replaceAll(":iD", "findByIdsResult.ID"); - queryFilterString = queryFilterString.replaceAll(":ID", "findByIdsResult.ID"); - } - queryFilterString = queryString + " AND (" + queryFilterString + ") > 0"; - - query = s.createQuery(queryFilterString); - mappedClass.getReadQuery().setQueryParameters(query, null, client.getBelongsToUserId()); - } - else { - query = s.createQuery(queryString); - } - } - - if (query != null) { - List queryResult = query.list(); - - if (result == null) - result = (List) HibernateUtils.cleanObject(queryResult); - else - result.addAll( (List) HibernateUtils.cleanObject(queryResult) ); - } - } - } catch (Exception e) { - log.error("Unable to findByIds", e); - } finally { - s.close(); - } - - return result; - **/ - } - - public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId) { - // TODO Auto-generated method stub - return null; - } - - public List findByExample(IPerceroObject theQueryObject, - List excludeProperties, String userId) { - // TODO Auto-generated method stub - return null; - } - - public List searchByExample(IPerceroObject theQueryObject, - List excludeProperties, String userId) { - // TODO Auto-generated method stub - return null; - } - - public IPerceroObject systemCreateObject(IPerceroObject perceroObject) { - // TODO Auto-generated method stub - return null; - } - - public IPerceroObject createObject(IPerceroObject perceroObject, String userId) { - // TODO Auto-generated method stub - return null; - } - - - - //////////////////////////////////////////////////// - // PUT - //////////////////////////////////////////////////// - public IPerceroObject putObject(IPerceroObject perceroObject, Map> changedFields, String userId) { -/* try { - Object result = JOhm.save(perceroObject); - return perceroObject; - } catch (Exception e) { - log.error("Unable to putObject", e); - }*/ - return null; - /** - boolean hasAccess = true; - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - if (mappedClass != null) { - if (mappedClass.getUpdateQuery() != null && StringUtils.hasText(mappedClass.getUpdateQuery().getQuery())){ - Session s = appSessionFactory.openSession(); - try { - Query updateFilter = s.createQuery(mappedClass.getUpdateQuery().getQuery()); - mappedClass.getUpdateQuery().setQueryParameters(updateFilter, perceroObject, client.getBelongsToUserId()); - Number updateFilterResult = (Number) updateFilter.uniqueResult(); - if (updateFilterResult == null || updateFilterResult.intValue() <= 0) - hasAccess = false; - } catch (Exception e) { - log.error("Error getting PUT AccessRights for object " + perceroObject.toString(), e); - hasAccess = false; - } finally { - s.close(); - } - } - } - - if (hasAccess) { - return systemPutObject(perceroObject, client, false); - } else { - return null; - } - **/ - } - - - - //////////////////////////////////////////////////// - // DELETE - //////////////////////////////////////////////////// - public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) { - // TODO Auto-generated method stub - return false; - } - - public List systemFindByExample( - IPerceroObject theQueryObject, List excludeProperties) { - // TODO Auto-generated method stub - return null; - } - - public List runQuery(MappedClass mappedClass, String queryName, - Object[] queryArguments, String clientId) { - // TODO Auto-generated method stub - return null; - } - - public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { - // TODO Auto-generated method stub - return null; - } - - public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map> changedFields) { - // TODO Auto-generated method stub - return null; - } - - public Boolean systemDeleteObject(IPerceroObject perceroObject) { - // TODO Auto-generated method stub - return null; - } - - public Object cleanObject(Object object, Session s, String userId) { - // TODO Auto-generated method stub - return null; - } - - public Map> getChangedMappedFields(IPerceroObject newObject) { - return null; - } -} diff --git a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java b/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java index e74656b..f43d1bb 100644 --- a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java @@ -1,5 +1,6 @@ package com.percero.agents.sync.services; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; @@ -30,6 +31,7 @@ import org.hibernate.criterion.Criterion; import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Restrictions; +import org.hibernate.impl.SessionFactoryImpl; import org.hibernate.impl.SessionImpl; import org.hibernate.type.Type; import org.springframework.beans.factory.annotation.Autowired; @@ -51,6 +53,7 @@ import com.percero.agents.sync.metadata.MappedFieldList; import com.percero.agents.sync.metadata.MappedFieldMap; import com.percero.agents.sync.metadata.MappedFieldPerceroObject; +import com.percero.agents.sync.metadata.MappedQuery; import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.ClassIDPair; import com.percero.agents.sync.vo.ClassIDPairs; @@ -94,17 +97,16 @@ public void setAppSessionFactory(SessionFactory value) { @SuppressWarnings({ "rawtypes", "unchecked" }) // TODO: @Transactional(readOnly=true) - public PerceroList getAllByName(Object aName, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception { + public PerceroList getAllByName(String className, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception { Session s = appSessionFactory.openSession(); try { returnTotal = true; - String aClassName = aName.toString(); Query countQuery = null; Query query = null; - Class theClass = MappedClass.forName(aName.toString()); + Class theClass = MappedClass.forName(className); IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); boolean isValidReadQuery = false; if (mappedClass != null) { if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { @@ -121,10 +123,10 @@ public PerceroList getAllByName(Object aName, Integer pageNumber */ if(mappedClass.getReadAllQuery() != null && mappedClass.getReadAllQuery().getQuery() != null && !mappedClass.getReadAllQuery().getQuery().isEmpty()){ if((mappedClass.getReadAllQuery() instanceof JpqlQuery)){ - throw new IllegalArgumentException("Illegal query type on:"+aClassName+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); + throw new IllegalArgumentException("Illegal query type on:"+className+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); } - log.debug("Using readAllQuery: "+aClassName); + log.debug("Using readAllQuery: "+className); String selectQueryString = mappedClass.getReadAllQuery().getQuery(); String countQueryString = "select count(*) from ("+selectQueryString+") as U"; @@ -145,8 +147,8 @@ public PerceroList getAllByName(Object aName, Integer pageNumber if (theClass != null) { String countQueryString = ""; if (returnTotal) - countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + aClassName + " getAllResult"; - String queryString = "SELECT getAllResult FROM " + aClassName + " getAllResult"; + countQueryString = "SELECT COUNT(getAllResult.ID) FROM " + className + " getAllResult"; + String queryString = "SELECT getAllResult FROM " + className + " getAllResult"; // If the Read Query/Filter uses the ID, then we need to check against each ID here. if (isValidReadQuery) { @@ -168,8 +170,8 @@ public PerceroList getAllByName(Object aName, Integer pageNumber countQuery = s.createQuery(countQueryFilterString); } query = s.createQuery(queryFilterString); - mappedClass.getReadQuery().setQueryParameters(query, null, userId); - mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); + mappedClass.getReadQuery().setQueryParameters(query.getQueryString(), null, userId); + mappedClass.getReadQuery().setQueryParameters(countQuery.getQueryString(), null, userId); } else { queryString += " ORDER BY getAllResult.ID"; @@ -188,7 +190,7 @@ public PerceroList getAllByName(Object aName, Integer pageNumber if (query != null) { - log.debug("Get ALL: "+aClassName); + log.debug("Get ALL: "+className); long t1 = new Date().getTime(); List list = query.list(); long t2 = new Date().getTime(); @@ -267,7 +269,7 @@ else if (theClass != null) { countQueryFilterString = countQueryString + " WHERE (" + countQueryFilterString + ") > 0"; countQuery = s.createQuery(countQueryFilterString); - mappedClass.getReadQuery().setQueryParameters(countQuery, null, userId); + mappedClass.getReadQuery().setQueryParameters(countQuery.getQueryString(), null, userId); } else { countQueryString += " ORDER BY ID"; @@ -293,28 +295,29 @@ else if (theClass != null) { return 0; } - public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String userId) { - Session s = appSessionFactory.openSession(); - try { - if (mappedClass != null) { - for(IMappedQuery nextQuery : mappedClass.queries) - { - if (queryName.equalsIgnoreCase(nextQuery.getQueryName())) - { - Query readFilter = s.createQuery(nextQuery.getQuery()); - nextQuery.setQueryParameters(readFilter, queryArguments, userId, queryArguments, (SessionImpl)s); - return processQueryResults(mappedClass.className + "_" + queryName, readFilter, readFilter.list()); - } - } - } - } catch (Exception e) { - log.error("Unable to runQuery", e); - } finally { - if (s != null && s.isOpen()) - s.close(); - } - - return null; + public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String userId) throws SyncException { + throw new SyncException(SyncException.METHOD_UNSUPPORTED, SyncException.METHOD_UNSUPPORTED_CODE); +// Session s = appSessionFactory.openSession(); +// try { +// if (mappedClass != null) { +// for(IMappedQuery nextQuery : mappedClass.queries) +// { +// if (queryName.equalsIgnoreCase(nextQuery.getQueryName())) +// { +// Query readFilter = s.createQuery(nextQuery.getQuery()); +// nextQuery.setQueryParameters(readFilter.getQueryString(), queryArguments, userId, queryArguments, (SessionImpl)s); +// return processQueryResults(mappedClass.className + "_" + queryName, readFilter, readFilter.list()); +// } +// } +// } +// } catch (Exception e) { +// log.error("Unable to runQuery", e); +// } finally { +// if (s != null && s.isOpen()) +// s.close(); +// } +// +// return null; } @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -415,7 +418,7 @@ public IPerceroObject findById(ClassIDPair classIdPair, String userId) { if (s == null) s = appSessionFactory.openSession(); Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); + mappedClass.getReadQuery().setQueryParameters(readFilter.getQueryString(), result, userId); Number readFilterResult = (Number) readFilter.uniqueResult(); if (readFilterResult == null || readFilterResult.intValue() <= 0) hasAccess = false; @@ -444,7 +447,7 @@ public IPerceroObject findById(ClassIDPair classIdPair, String userId) { return null; } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "rawtypes" }) public IPerceroObject systemGetById(ClassIDPair classIdPair) { Session s = null; try { @@ -670,7 +673,7 @@ public Boolean getReadAccess(ClassIDPair classIdPair, String userId) { if (mappedClass != null) { if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, parent, userId); + mappedClass.getReadQuery().setQueryParameters(readFilter.getQueryString(), parent, userId); Number readFilterResult = (Number) readFilter.uniqueResult(); if (readFilterResult == null || readFilterResult.intValue() <= 0) hasAccess = false; @@ -706,7 +709,7 @@ public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { if (mappedClass != null) { if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); - mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, parent, userId); + mappedClass.getDeleteQuery().setQueryParameters(deleteFilter.getQueryString(), parent, userId); Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) hasAccess = false; @@ -774,7 +777,7 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) IPerceroObject nextCachedResult = itrCachedResults.next(); if (isValidReadQuery) { Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, nextCachedResult, userId); + mappedClass.getReadQuery().setQueryParameters(readFilter.getQueryString(), nextCachedResult, userId); Number readFilterResult = (Number) readFilter.uniqueResult(); if (readFilterResult == null || readFilterResult.intValue() <= 0) hasAccess = false; @@ -851,7 +854,7 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) queryFilterString = queryString + " AND (" + queryFilterString + ") > 0"; query = s.createQuery(queryFilterString); - mappedClass.getReadQuery().setQueryParameters(query, null, userId); + mappedClass.getReadQuery().setQueryParameters(query.getQueryString(), null, userId); } else { query = s.createQuery(queryString); @@ -947,7 +950,7 @@ else if (nextConstraint instanceof List) { if (mappedClass != null) { if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())){ Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter, result, userId); + mappedClass.getReadQuery().setQueryParameters(readFilter.getQueryString(), result, userId); Number readFilterResult = (Number) readFilter.uniqueResult(); if (readFilterResult == null || readFilterResult.intValue() <= 0) hasAccess = false; @@ -973,7 +976,7 @@ else if (nextConstraint instanceof List) { // TODO: Add permissions check. @SuppressWarnings({ "unchecked" }) - public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId) { + public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId, Boolean shellOnly) { Session s = appSessionFactory.openSession(); try { Criteria criteria = s.createCriteria(theQueryObject.getClass()); @@ -1107,9 +1110,9 @@ else if (fieldObject instanceof Collection) { } } } - Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); while(itrToOneFields.hasNext()) { - MappedField nextMappedField = itrToOneFields.next(); + MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); if (fieldObject != null) { if (fieldObject instanceof IPerceroObject) { @@ -1198,8 +1201,16 @@ public IPerceroObject createObject(IPerceroObject perceroObject, String userId) if (mappedClass.getCreateQuery() != null && StringUtils.hasText(mappedClass.getCreateQuery().getQuery())){ Session s = appSessionFactory.openSession(); try { + IMappedQuery createQuery = mappedClass.getCreateQuery(); Query createFilter = s.createQuery(mappedClass.getCreateQuery().getQuery()); - mappedClass.getCreateQuery().setQueryParameters(createFilter, perceroObject, userId); + if (createQuery instanceof JpqlQuery) { + createFilter = ((JpqlQuery)createFilter).createQuery(perceroObject, userId, null, (SessionImpl) s); + } + else { + String createFilterString = mappedClass.getCreateQuery().setQueryParameters(createFilter.getQueryString(), perceroObject, userId); + createFilter = s.createQuery(createFilterString); + } + Number createFilterResult = (Number) createFilter.uniqueResult(); if (createFilterResult == null || createFilterResult.intValue() <= 0) hasAccess = false; @@ -1224,7 +1235,7 @@ public IPerceroObject createObject(IPerceroObject perceroObject, String userId) //////////////////////////////////////////////////// // PUT //////////////////////////////////////////////////// - public IPerceroObject putObject(IPerceroObject perceroObject, Map> changedFields, String userId) throws SyncException { + public T putObject(T perceroObject, Map> changedFields, String userId) throws SyncException { boolean hasAccess = true; IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); @@ -1233,7 +1244,7 @@ public IPerceroObject putObject(IPerceroObject perceroObject, Map itrToOneFields = mappedClass.toOneFields.iterator(); + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); while(itrToOneFields.hasNext()) { - MappedField nextMappedField = itrToOneFields.next(); + MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); if (fieldObject != null) { if (fieldObject instanceof IPerceroObject) { @@ -1412,7 +1423,7 @@ public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws Sy if (mappedClass != null) { if (mappedClass.getDeleteQuery() != null && StringUtils.hasText(mappedClass.getDeleteQuery().getQuery())){ Query deleteFilter = s.createQuery(mappedClass.getDeleteQuery().getQuery()); - mappedClass.getDeleteQuery().setQueryParameters(deleteFilter, perceroObject, userId); + mappedClass.getDeleteQuery().setQueryParameters(deleteFilter.getQueryString(), perceroObject, userId); Number deleteFilterResult = (Number) deleteFilter.uniqueResult(); if (deleteFilterResult == null || deleteFilterResult.intValue() <= 0) hasAccess = false; @@ -1488,9 +1499,9 @@ else if (fieldObject instanceof Collection) { } } } - Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); while(itrToOneFields.hasNext()) { - MappedField nextMappedField = itrToOneFields.next(); + MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); if (fieldObject != null) { if (fieldObject instanceof IPerceroObject) { @@ -1685,4 +1696,54 @@ private Collection retrieveObjectsNotInCollection(Collection baseList, Collectio return result; } + + + public List getAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException { +// throw new SyncException(SyncException.METHOD_UNSUPPORTED, SyncException.METHOD_UNSUPPORTED_CODE); + try { + IPerceroObject exampleObject = (IPerceroObject) mappedField.getMappedClass().clazz.newInstance(); + IPerceroObject targetObject = (IPerceroObject) Class.forName(targetClassIdPair.getClassName()).newInstance(); + targetObject.setID(targetClassIdPair.getID()); + mappedField.getSetter().invoke(exampleObject, targetObject); + return findByExample(exampleObject, null, userId, shellOnly); + } catch (InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return null; + + } + + @Override + public List findAllRelatedObjects( + IPerceroObject perceroObject, MappedField mappedField, + Boolean shellOnly, String userId) throws SyncException { + throw new SyncException(SyncException.METHOD_UNSUPPORTED, SyncException.METHOD_UNSUPPORTED_CODE); + } + + @Override + public IPerceroObject cleanObject(IPerceroObject perceroObject, + String userId) throws SyncException { + throw new SyncException(SyncException.METHOD_UNSUPPORTED, SyncException.METHOD_UNSUPPORTED_CODE); + } + + @Override + public List cleanObject( + List perceroObjects, String userId) + throws SyncException { + throw new SyncException(SyncException.METHOD_UNSUPPORTED, SyncException.METHOD_UNSUPPORTED_CODE); + } } diff --git a/src/main/java/com/percero/agents/sync/services/SyncAgentService.java b/src/main/java/com/percero/agents/sync/services/SyncAgentService.java index 37ff738..34dff38 100644 --- a/src/main/java/com/percero/agents/sync/services/SyncAgentService.java +++ b/src/main/java/com/percero/agents/sync/services/SyncAgentService.java @@ -263,26 +263,25 @@ public String getDataId(String clientId) throws Exception { } - public PerceroList getAllByName(Object aName, Boolean returnTotal, String clientId) throws Exception { - return getAllByName(aName, null, null, returnTotal, clientId); + public PerceroList getAllByName(String className, Boolean returnTotal, String clientId) throws Exception { + return getAllByName(className, null, null, returnTotal, clientId); } @SuppressWarnings("rawtypes") - public PerceroList getAllByName(Object aName, Integer pageNumber, Integer pageSize, Boolean returnTotal, String clientId) throws Exception { + public PerceroList getAllByName(String className, Integer pageNumber, Integer pageSize, Boolean returnTotal, String clientId) throws Exception { Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); - String aClassName = aName.toString(); - Class theClass = MappedClass.forName(aClassName); + Class theClass = MappedClass.forName(className); // Get the MappedClass and determine which DataProvider provides data for this object. IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(aName.toString()); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); String userId = accessManager.getClientUserId(clientId); - PerceroList result = dataProvider.getAllByName(aName, pageNumber, pageSize, returnTotal, userId); + PerceroList result = dataProvider.getAllByName(className, pageNumber, pageSize, returnTotal, userId); if (result != null) { // Register an Zero ID object to indicate that this user wants updates to ALL objects of this type. @@ -411,20 +410,20 @@ public Object findByExample(Object theQueryObject, if (mappedClass != null) { String userId = accessManager.getClientUserId(clientId); IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - return dataProvider.findByExample((IPerceroObject) theQueryObject, excludeProperties, userId); + return dataProvider.findByExample((IPerceroObject) theQueryObject, excludeProperties, userId, false); } } return null; } - public List systemFindByExample(Object theQueryObject, List excludeProperties) { + public List systemFindByExample(Object theQueryObject, List excludeProperties) throws SyncException { if (theQueryObject instanceof IPerceroObject) { IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(theQueryObject.getClass().getCanonicalName()); if (mappedClass != null) { IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - return dataProvider.systemFindByExample((IPerceroObject) theQueryObject, excludeProperties); + return dataProvider.findByExample((IPerceroObject) theQueryObject, excludeProperties, null, false); } } @@ -444,7 +443,11 @@ public Object findUnique(Object theQueryObject, String clientId) throws Exceptio String userId = accessManager.getClientUserId(clientId); IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - IPerceroObject result = dataProvider.findUnique((IPerceroObject) theQueryObject, userId); + List results = dataProvider.findByExample((IPerceroObject) theQueryObject, null, userId, false); + IPerceroObject result = null; + if (results != null && !results.isEmpty()) { + result = results.get(0); + } if (result != null) { postGetHelper.postGetObject(result, userId, clientId); @@ -473,7 +476,7 @@ public Object searchByExample(Object theQueryObject, String userId = accessManager.getClientUserId(clientId); IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - List result = dataProvider.searchByExample((IPerceroObject) theQueryObject, excludeProperties, userId); + List result = dataProvider.findByExample((IPerceroObject) theQueryObject, excludeProperties, userId, false); if (result != null && result.size() > 0) postGetHelper.postGetObject(result, userId, clientId); @@ -515,7 +518,7 @@ public IPerceroObject systemGetById(String aClassName, String anId) {//throws Ex MappedClass mappedClass = mcm.getMappedClassByClassName(aClassName); IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - IPerceroObject result = dataProvider.systemGetById(new ClassIDPair(anId, aClassName)); + IPerceroObject result = dataProvider.findById(new ClassIDPair(anId, aClassName), null); return result; } @@ -526,12 +529,13 @@ public IPerceroObject systemGetById(ClassIDPair cip) { //throws Exception { MappedClass mappedClass = mcm.getMappedClassByClassName(cip.getClassName()); IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - IPerceroObject result = dataProvider.systemGetById(cip); + IPerceroObject result = dataProvider.findById(cip, null); return result; } - public T systemGetByObject(IPerceroObject perceroObject) {//throws Exception { + @SuppressWarnings("unchecked") + public T systemGetByObject(T perceroObject) {//throws Exception { // Get the MappedClass and determine which DataProvider provides data for this object. if (perceroObject == null || !StringUtils.hasText(perceroObject.getID())) { return null; @@ -541,7 +545,7 @@ public T systemGetByObject(IPerceroObject perceroObje MappedClass mappedClass = mcm.getMappedClassByClassName(className); IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - T result = dataProvider.systemGetById(new ClassIDPair(perceroObject.getID(), className)); + T result = (T) dataProvider.findById(new ClassIDPair(perceroObject.getID(), className), null); return result; } @@ -557,7 +561,7 @@ public T systemGetByObject(IPerceroObject perceroObje * @return List * @throws Exception */ - public List getHistory(ClassIDPair classIdPair, String clientId) throws Exception { + public List getHistory(ClassIDPair classIdPair, String clientId) throws Exception { return getHistory(classIdPair.getClassName(), classIdPair.getID(), clientId); } @@ -573,7 +577,7 @@ public List getHistory(ClassIDPair classIdPair, String clientId) throws * @return List * @throws Exception */ - public List getHistory(String aClassName, String anId, String clientId) throws Exception { + public List getHistory(String aClassName, String anId, String clientId) throws Exception { Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); @@ -782,7 +786,7 @@ public boolean systemPutObject(IPerceroObject perceroObject, String transactionI IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); changedFields = dataProvider.getChangedMappedFields(perceroObject); if (changedFields == null || changedFields.size() > 0) { - result = dataProvider.systemPutObject(perceroObject, changedFields); + result = dataProvider.putObject(perceroObject, changedFields, null); if (result != null) { // Now record the updated object. @@ -927,7 +931,7 @@ public ServerResponse createObject(IPerceroObject perceroObject, String clientId return response; } - public T systemCreateObject(IPerceroObject perceroObject, String userId) throws SyncException { + public T systemCreateObject(T perceroObject, String userId) throws SyncException { log.debug("Create: " + perceroObject.getClass().getName() + ": " + perceroObject.getID()); @@ -936,7 +940,7 @@ public T systemCreateObject(IPerceroObject perceroObj IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - T result = dataProvider.systemCreateObject(perceroObject); + T result = dataProvider.createObject(perceroObject, null); if (result != null) { Date updateDate = new Date(); @@ -1035,7 +1039,7 @@ public ServerResponse deleteObject(ClassIDPair theClassIdPair, String clientId, hasAccess = dataProvider.getDeleteAccess(theClassIdPair, userId); if (hasAccess) { - IPerceroObject perceroObject = dataProvider.systemGetById(theClassIdPair); + IPerceroObject perceroObject = dataProvider.findById(theClassIdPair, null); if (perceroObject == null) { response.setIsSuccessful(true); return response; @@ -1078,7 +1082,7 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, if (mappedClass != null) { IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - perceroObject = (IPerceroObject) dataProvider.systemGetById(new ClassIDPair(perceroObject.getID(), perceroObject.getClass().getCanonicalName())); + perceroObject = (IPerceroObject) dataProvider.findById(new ClassIDPair(perceroObject.getID(), perceroObject.getClass().getCanonicalName()), null); if (perceroObject == null) { return true; @@ -1100,7 +1104,7 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, IPerceroObject tempObject = (IPerceroObject) nextRemoveMappedFieldRef.getMappedClass().clazz.newInstance(); nextRemoveMappedFieldRef.getSetter().invoke(tempObject, perceroObject); IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextRemoveMappedFieldRef.getMappedClass().dataProviderName); - List referencingObjects = dataProviderRef.systemFindByExample(tempObject, null); + List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); Iterator itrReferencingObjects = referencingObjects.iterator(); while (itrReferencingObjects.hasNext()) { IPerceroObject nextReferencingObject = itrReferencingObjects.next(); @@ -1112,7 +1116,7 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, IPerceroObject tempObject = (IPerceroObject) nextRemoveMappedFieldRef.getMappedClass().clazz.newInstance(); nextRemoveMappedFieldRef.getSetter().invoke(tempObject, perceroObject); IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextRemoveMappedFieldRef.getMappedClass().dataProviderName); - List referencingObjects = dataProviderRef.systemFindByExample(tempObject, null); + List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); Iterator itrReferencingObjects = referencingObjects.iterator(); while (itrReferencingObjects.hasNext()) { IPerceroObject nextReferencingObject = itrReferencingObjects.next(); @@ -1143,7 +1147,7 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, IPerceroObject tempObject = (IPerceroObject) nextToNullMappedFieldRef.getMappedClass().clazz.newInstance(); nextToNullMappedFieldRef.getSetter().invoke(tempObject, perceroObject); IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextToNullMappedFieldRef.getMappedClass().dataProviderName); - List referencingObjects = dataProviderRef.systemFindByExample(tempObject, null); + List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); Iterator itrReferencingObjects = referencingObjects.iterator(); while (itrReferencingObjects.hasNext()) { IPerceroObject nextReferencingObject = itrReferencingObjects.next(); @@ -1156,7 +1160,7 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, IPerceroObject tempObject = (IPerceroObject) nextToNullMappedFieldRef.getMappedClass().clazz.newInstance(); nextToNullMappedFieldRef.getSetter().invoke(tempObject, perceroObject); IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextToNullMappedFieldRef.getMappedClass().dataProviderName); - List referencingObjects = dataProviderRef.systemFindByExample(tempObject, null); + List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); Iterator itrReferencingObjects = referencingObjects.iterator(); while (itrReferencingObjects.hasNext()) { IPerceroObject nextReferencingObject = itrReferencingObjects.next(); @@ -1170,9 +1174,9 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, } } - Iterator itrToOneFieldsToUpdate = mappedClass.toOneFields.iterator(); + Iterator itrToOneFieldsToUpdate = mappedClass.toOneFields.iterator(); while (itrToOneFieldsToUpdate.hasNext()) { - MappedField nextToOneField = itrToOneFieldsToUpdate.next(); + MappedFieldPerceroObject nextToOneField = itrToOneFieldsToUpdate.next(); if (nextToOneField instanceof MappedFieldPerceroObject) { MappedFieldPerceroObject nextPerceroObjectField = (MappedFieldPerceroObject) nextToOneField; IPerceroObject toOneObject = (IPerceroObject) nextPerceroObjectField.getGetter().invoke(perceroObject); @@ -1197,7 +1201,7 @@ else if (nextToManyField instanceof MappedFieldList) { } // If the result has been set to false, it means that deletion/update of one of the related objects failed. - if (result && dataProvider.systemDeleteObject(perceroObject)) { + if (result && dataProvider.deleteObject(BaseDataObject.toClassIdPair(perceroObject), null)) { // Also store historical record, if necessary. if (storeHistory && (perceroObject instanceof IHistoryObject)) { diff --git a/src/main/java/com/percero/agents/sync/vo/ClassIDPairs.java b/src/main/java/com/percero/agents/sync/vo/ClassIDPairs.java index 2a5b1b3..993c858 100644 --- a/src/main/java/com/percero/agents/sync/vo/ClassIDPairs.java +++ b/src/main/java/com/percero/agents/sync/vo/ClassIDPairs.java @@ -36,6 +36,13 @@ public void setClassName(String value) { className = value; } + public void addId(String id) { + if (ids == null) { + ids = new ArrayList(1); + } + ids.add(id); + } + public void readExternal(ObjectInput input) { try { setClassName(input.readUTF()); diff --git a/src/main/java/com/percero/util/DateUtils.java b/src/main/java/com/percero/util/DateUtils.java new file mode 100644 index 0000000..46b5bf3 --- /dev/null +++ b/src/main/java/com/percero/util/DateUtils.java @@ -0,0 +1,14 @@ +package com.percero.util; + +public class DateUtils { + + public static java.sql.Date utilDateToSqlDate(java.util.Date utilDate) { + if (utilDate != null) { + return new java.sql.Date(utilDate.getTime()); + } + else { + return null; + } + } + +} diff --git a/src/main/resources/spring/percero-spring-config.xml b/src/main/resources/spring/percero-spring-config.xml index 6f3b4fb..9ac29ce 100644 --- a/src/main/resources/spring/percero-spring-config.xml +++ b/src/main/resources/spring/percero-spring-config.xml @@ -96,6 +96,11 @@ + From 62332012fa09fcff09a8b16b39193a4067f47c66 Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Wed, 16 Sep 2015 16:20:33 -0700 Subject: [PATCH 17/20] wip --- .gitignore | 4 ++ pom.xml | 4 +- .../jobs/UpdateTableConnectionFactory.java | 2 +- .../sync/jobs/UpdateTableProcessor.java | 42 ++++++++++++++----- .../jobs/UpdateTableProcessorFactory.java | 11 +++-- .../percero/client/AStackClientFactory.java | 6 ++- 6 files changed, 51 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 54b685e..c576a04 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ target/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + +/.settings/ +/.project +/.classpath diff --git a/pom.xml b/pom.xml index f7fd561..accbb43 100644 --- a/pom.xml +++ b/pom.xml @@ -5,9 +5,9 @@ 4.0.0 - io.activestack + org.activestack syncengine - 1.1.15-SNAPSHOT + 1.1.17-updatetable-SNAPSHOT 3.2.4.RELEASE diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java index d5f5cd7..8c3fa0f 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java @@ -36,7 +36,7 @@ public void setUsername(String val){ } @Autowired - @Value("$pf{updateTable.username}") + @Value("$pf{updateTable.password}") private String password; public void setPassword(String val){ this.password = val; diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java index a30c9e5..28a55b8 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java @@ -1,24 +1,36 @@ package com.percero.agents.sync.jobs; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import javax.persistence.Table; + +import org.apache.log4j.Logger; +import org.joda.time.DateTime; + import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.cache.CacheManager; +import com.percero.agents.sync.helpers.PostCreateHelper; import com.percero.agents.sync.helpers.PostDeleteHelper; import com.percero.agents.sync.helpers.PostPutHelper; -import com.percero.agents.sync.metadata.*; +import com.percero.agents.sync.metadata.IMappedClassManager; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClassManagerFactory; +import com.percero.agents.sync.metadata.MappedField; +import com.percero.agents.sync.metadata.MappedFieldPerceroObject; import com.percero.agents.sync.services.DataProviderManager; import com.percero.agents.sync.services.IDataProvider; import com.percero.agents.sync.vo.ClassIDPair; import com.percero.framework.bl.IManifest; import com.percero.framework.vo.IPerceroObject; -import org.apache.log4j.Logger; -import org.joda.time.DateTime; - -import javax.persistence.Table; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.*; /** * Responsible for querying an update table and processing the rows. @@ -33,6 +45,7 @@ public class UpdateTableProcessor { private UpdateTableConnectionFactory connectionFactory; private PostDeleteHelper postDeleteHelper; private PostPutHelper postPutHelper; + private PostCreateHelper postCreateHelper; private IManifest manifest; private CacheManager cacheManager; private DataProviderManager dataProviderManager; @@ -43,6 +56,7 @@ public UpdateTableProcessor(String tableName, IManifest manifest, PostDeleteHelper postDeleteHelper, PostPutHelper postPutHelper, + PostCreateHelper postCreateHelper, CacheManager cacheManager, DataProviderManager dataProviderManager, IAccessManager accessManager) @@ -51,6 +65,7 @@ public UpdateTableProcessor(String tableName, this.connectionFactory = connectionFactory; this.postDeleteHelper = postDeleteHelper; this.postPutHelper = postPutHelper; + this.postCreateHelper = postCreateHelper; this.manifest = manifest; this.cacheManager = cacheManager; this.dataProviderManager= dataProviderManager; @@ -186,7 +201,12 @@ private void processUpdates(String className, Collection Ids) throws Exc */ private boolean processInsertSingle(UpdateTableRow row) throws Exception{ Class clazz = getClassForTableName(row.getTableName()); - postPutHelper.postPutObject(new ClassIDPair(row.getRowId(), clazz.getCanonicalName()), null, null, true, null); + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(clazz.getCanonicalName()); + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); + IPerceroObject perceroObject = dataProvider.systemGetById(new ClassIDPair(row.getRowId(), clazz.getCanonicalName()), true); + + postCreateHelper.postCreateObject(perceroObject, null, null, true); updateReferences(clazz.getName()); return true; } diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java index cbf6b89..c691b7f 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java @@ -1,13 +1,15 @@ package com.percero.agents.sync.jobs; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.cache.CacheManager; +import com.percero.agents.sync.helpers.PostCreateHelper; import com.percero.agents.sync.helpers.PostDeleteHelper; import com.percero.agents.sync.helpers.PostPutHelper; import com.percero.agents.sync.services.DataProviderManager; import com.percero.framework.bl.IManifest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; /** * Creates UpdateTableProcessor for the poller @@ -28,6 +30,9 @@ public class UpdateTableProcessorFactory { @Autowired PostPutHelper postPutHelper; + @Autowired + PostCreateHelper postCreateHelper; + @Autowired CacheManager cacheManager; @@ -39,6 +44,6 @@ public class UpdateTableProcessorFactory { public UpdateTableProcessor getProcessor(String tableName){ return new UpdateTableProcessor(tableName, connectionFactory, manifest, - postDeleteHelper, postPutHelper, cacheManager, dataProviderManager, accessManager); + postDeleteHelper, postPutHelper, postCreateHelper, cacheManager, dataProviderManager, accessManager); } } diff --git a/src/test/java/com/percero/client/AStackClientFactory.java b/src/test/java/com/percero/client/AStackClientFactory.java index 2982c9f..18f4006 100644 --- a/src/test/java/com/percero/client/AStackClientFactory.java +++ b/src/test/java/com/percero/client/AStackClientFactory.java @@ -1,5 +1,6 @@ package com.percero.client; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -12,7 +13,10 @@ public class AStackClientFactory { @Autowired AStackRPCService rpcService; + @Autowired + ConnectionFactory connectionFactory; + public AStackClient getClient(){ - return new AStackClient(rpcService); + return new AStackClient(rpcService, connectionFactory); } } From d9da7813848c3a4b0e5f86f8c9988b0318e73242 Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Thu, 17 Sep 2015 14:10:39 -0700 Subject: [PATCH 18/20] wip - updateTable --- .../sync/access/RedisAccessManager.java | 2 +- .../agents/sync/cache/CacheManager.java | 299 ++++++++++++----- .../sync/datastore/ICacheDataStore.java | 3 + .../sync/jobs/UpdateTableProcessor.java | 301 +++++++++++++----- .../jobs/UpdateTableProcessorFactory.java | 6 +- .../agents/sync/metadata/MappedClass.java | 130 ++++++++ .../agents/sync/services/DAODataProvider.java | 123 +++++-- .../sync/services/DataProviderManager.java | 13 +- .../agents/sync/services/IDataProvider.java | 4 + .../sync/services/RedisDataProvider.java | 15 + .../sync/services/SyncAgentDataProvider.java | 96 ++++-- .../sync/services/SyncAgentService.java | 53 ++- 12 files changed, 782 insertions(+), 263 deletions(-) diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index ba110e1..db44c71 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -842,7 +842,7 @@ private Long upsertRedisAccessJournal(String userId, String clientId, String cla cacheDataStore.addSetValue(clientAccessJournalKey, RedisKeyUtils.objectId(className, classId)); // Add to the class's AccessJournals set - if(classId != null && !classId.isEmpty() && !classId.equals("0")) { + if(classId != null && !classId.isEmpty()) { // && !classId.equals("0")) { log.info("Adding to class AccessJournals: "+classId); String classAccessJournalKey = RedisKeyUtils.classAccessJournal(className); cacheDataStore.addSetValue(classAccessJournalKey, classId); diff --git a/src/main/java/com/percero/agents/sync/cache/CacheManager.java b/src/main/java/com/percero/agents/sync/cache/CacheManager.java index 6d45b17..83f2cf1 100644 --- a/src/main/java/com/percero/agents/sync/cache/CacheManager.java +++ b/src/main/java/com/percero/agents/sync/cache/CacheManager.java @@ -1,11 +1,15 @@ package com.percero.agents.sync.cache; import com.percero.agents.sync.access.RedisKeyUtils; -import com.percero.agents.sync.datastore.RedisDataStore; +import com.percero.agents.sync.datastore.ICacheDataStore; +import com.percero.agents.sync.hibernate.SyncHibernateUtils; import com.percero.agents.sync.metadata.IMappedClassManager; import com.percero.agents.sync.metadata.MappedClass; import com.percero.agents.sync.metadata.MappedClassManagerFactory; import com.percero.agents.sync.metadata.MappedField; +import com.percero.agents.sync.metadata.MappedFieldPerceroObject; +import com.percero.agents.sync.services.DataProviderManager; +import com.percero.agents.sync.services.IDataProvider; import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.ClassIDPair; import com.percero.framework.vo.IPerceroObject; @@ -26,7 +30,7 @@ public class CacheManager { private static Logger logger = Logger.getLogger(CacheManager.class); @Autowired - RedisDataStore redisDataStore; + ICacheDataStore cacheDataStore; @Autowired Long cacheTimeout = Long.valueOf(60 * 60 * 24 * 14); // Two weeks @@ -34,15 +38,15 @@ public class CacheManager { public void updateCachedObject(IPerceroObject perceroObject, Map> changedFields){ // TODO: Field-level updates could be REALLY useful here. Would avoid A TON of UNNECESSARY work... try { - if (cacheTimeout > 0) { - // TODO: Also need to update the caches of anything object that is related to this object. - String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); - if (redisDataStore.hasKey(key)) { - redisDataStore.setValue(key, ((BaseDataObject) perceroObject).toJson()); - } - - // Iterate through each changed object and reset the cache for that object. - if (changedFields != null) { + if (cacheTimeout > 0) { + // TODO: Also need to update the caches of anything object that is related to this object. + String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); + if (cacheDataStore.hasKey(key)) { + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + } + + // Iterate through each changed object and reset the cache for that object. + if (changedFields != null) { // Iterator>> itrChangedFieldEntrySet = changedFields.entrySet().iterator(); // Set keysToDelete = new HashSet(); // while (itrChangedFieldEntrySet.hasNext()) { @@ -53,85 +57,204 @@ public void updateCachedObject(IPerceroObject perceroObject, Map itrChangedFieldKeyset = changedFields.keySet().iterator(); - Set keysToDelete = new HashSet(); - while (itrChangedFieldKeyset.hasNext()) { - ClassIDPair thePair = itrChangedFieldKeyset.next(); - if (!thePair.comparePerceroObject(perceroObject)) { - String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); - keysToDelete.add(nextKey); - } - } - - if (!keysToDelete.isEmpty()) { - redisDataStore.deleteKeys(keysToDelete); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } else { - // No changedFields? We should never get here? - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - Iterator itrToManyFields = mappedClass.toManyFields.iterator(); - while (itrToManyFields.hasNext()) { - MappedField nextMappedField = itrToManyFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject) fieldObject).getID()); - if (redisDataStore.hasKey(nextKey)) { - redisDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while (itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject) nextListObject).getID()); - if (redisDataStore.hasKey(nextKey)) { - redisDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - } - } - } - } - Iterator itrToOneFields = mappedClass.toOneFields.iterator(); - while (itrToOneFields.hasNext()) { - MappedField nextMappedField = itrToOneFields.next(); - Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); - if (fieldObject != null) { - if (fieldObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject) fieldObject).getID()); - if (redisDataStore.hasKey(nextKey)) { - redisDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while (itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject) nextListObject).getID()); - if (redisDataStore.hasKey(nextKey)) { - redisDataStore.deleteKey(nextKey); - // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? - //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); - } - } - } - } - } - } - } - } + Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); + Set keysToDelete = new HashSet(); + while (itrChangedFieldKeyset.hasNext()) { + ClassIDPair thePair = itrChangedFieldKeyset.next(); + if (!thePair.comparePerceroObject(perceroObject)) { + String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); + keysToDelete.add(nextKey); + } + } + + if (!keysToDelete.isEmpty()) { + cacheDataStore.deleteKeys(keysToDelete); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + else { + // No changedFields? We should never get here? + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + Iterator itrToManyFields = mappedClass.toManyFields.iterator(); + while(itrToManyFields.hasNext()) { + MappedField nextMappedField = itrToManyFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + } + } + } + } + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + while(itrToOneFields.hasNext()) { + MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); + if (cacheDataStore.hasKey(nextKey)) { + cacheDataStore.deleteKey(nextKey); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } + } + } + } + } + } + } } catch (Exception e){ logger.warn(e.getMessage(), e); } } + + public void handleDeletedObject(IPerceroObject perceroObject, String className, Boolean isShellObject) { + if (cacheTimeout > 0) { + try { + Set keysToDelete = new HashSet(); + + String key = RedisKeyUtils.classIdPair(className, perceroObject.getID()); + keysToDelete.add(key); + + Set relatedClassIdPairs = getRelatedClassIdPairs(perceroObject, className, isShellObject); + Iterator itrRelatedClassIdPairs = relatedClassIdPairs.iterator(); + while (itrRelatedClassIdPairs.hasNext()) { + ClassIDPair nextRelatedClassIdPair = itrRelatedClassIdPairs.next(); + String nextKey = RedisKeyUtils.classIdPair(nextRelatedClassIdPair.getClassName(), nextRelatedClassIdPair.getID()); + keysToDelete.add(nextKey); + } + + if (!keysToDelete.isEmpty()) { + cacheDataStore.deleteKeys(keysToDelete); + // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? + //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + } + + public void deleteObjectFromCache(ClassIDPair classIdPair) { + String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); + cacheDataStore.deleteKey(key); + } + + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Set getRelatedClassIdPairs(IPerceroObject perceroObject, String className, Boolean isShellObject) throws Exception { + Set results = new HashSet(); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); + + Iterator itrToManyFields = mappedClass.toManyFields.iterator(); + while(itrToManyFields.hasNext()) { + MappedField nextMappedField = itrToManyFields.next(); + + // If this is a SHELL object, then we need to get ALL objects of this MappedField type. + if (isShellObject) { + // If NO reverse mapped field, then nothing to update. + if (nextMappedField.getReverseMappedField() != null) { + MappedClass reverseMappedClass = nextMappedField.getReverseMappedField().getMappedClass(); + IDataProvider reverseDataProvider = DataProviderManager.getInstance().getDataProviderByName(reverseMappedClass.className); + Set allClassIdPairs = reverseDataProvider.getAllClassIdPairsByName(reverseMappedClass.className); + Iterator itrAllClassIdPairs = allClassIdPairs.iterator(); + while (itrAllClassIdPairs.hasNext()) { + ClassIDPair nextAllClassIdPair = itrAllClassIdPairs.next(); + results.add(nextAllClassIdPair); + } + } + } + else { + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + results.add(new ClassIDPair(((IPerceroObject)fieldObject).getID(), fieldObject.getClass().getCanonicalName())); + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + results.add(new ClassIDPair(((IPerceroObject)nextListObject).getID(), nextListObject.getClass().getCanonicalName())); + } + } + } + } + } + } + Iterator itrToOneFields = mappedClass.toOneFields.iterator(); + while(itrToOneFields.hasNext()) { + MappedFieldPerceroObject nextMappedField = itrToOneFields.next(); + + // If this is a SHELL object, then we need to get ALL objects of this MappedField type. + if (isShellObject) { + // If NO reverse mapped field, then nothing to update. + if (nextMappedField.getReverseMappedField() != null) { + MappedClass reverseMappedClass = nextMappedField.getReverseMappedField().getMappedClass(); + IDataProvider reverseDataProvider = DataProviderManager.getInstance().getDataProviderByName(reverseMappedClass.className); + Set allClassIdPairs = reverseDataProvider.getAllClassIdPairsByName(reverseMappedClass.className); + Iterator itrAllClassIdPairs = allClassIdPairs.iterator(); + while (itrAllClassIdPairs.hasNext()) { + ClassIDPair nextAllClassIdPair = itrAllClassIdPairs.next(); + results.add(nextAllClassIdPair); + } + } + } + else { + Object fieldObject = nextMappedField.getGetter().invoke(perceroObject); + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + results.add(new ClassIDPair(((IPerceroObject)fieldObject).getID(), fieldObject.getClass().getCanonicalName())); + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + results.add(new ClassIDPair(((IPerceroObject)nextListObject).getID(), nextListObject.getClass().getCanonicalName())); + } + } + } + } + } + } + + return results; + } } diff --git a/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java b/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java index 06666ea..614ed8f 100644 --- a/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java +++ b/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java @@ -84,6 +84,9 @@ public abstract void setAllHashValues(String key, @Transactional public abstract Boolean getSetIsEmpty(String key); + @Transactional + public Long getSetSize( final String key ); + @Transactional public abstract Long removeSetValueAndGetSize(String key, Object value); diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java index 28a55b8..e6288e6 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java @@ -6,10 +6,13 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; -import java.util.List; +import java.util.Iterator; +import java.util.Map; import java.util.Random; import java.util.Set; +import java.util.UUID; import javax.persistence.Table; @@ -28,9 +31,11 @@ import com.percero.agents.sync.metadata.MappedFieldPerceroObject; import com.percero.agents.sync.services.DataProviderManager; import com.percero.agents.sync.services.IDataProvider; +import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.ClassIDPair; import com.percero.framework.bl.IManifest; import com.percero.framework.vo.IPerceroObject; +import com.percero.framework.vo.PerceroList; /** * Responsible for querying an update table and processing the rows. @@ -45,7 +50,6 @@ public class UpdateTableProcessor { private UpdateTableConnectionFactory connectionFactory; private PostDeleteHelper postDeleteHelper; private PostPutHelper postPutHelper; - private PostCreateHelper postCreateHelper; private IManifest manifest; private CacheManager cacheManager; private DataProviderManager dataProviderManager; @@ -56,7 +60,6 @@ public UpdateTableProcessor(String tableName, IManifest manifest, PostDeleteHelper postDeleteHelper, PostPutHelper postPutHelper, - PostCreateHelper postCreateHelper, CacheManager cacheManager, DataProviderManager dataProviderManager, IAccessManager accessManager) @@ -65,11 +68,36 @@ public UpdateTableProcessor(String tableName, this.connectionFactory = connectionFactory; this.postDeleteHelper = postDeleteHelper; this.postPutHelper = postPutHelper; - this.postCreateHelper = postCreateHelper; this.manifest = manifest; this.cacheManager = cacheManager; this.dataProviderManager= dataProviderManager; this.accessManager = accessManager; + + insertTasks(100, "9"); + } + + + private void insertTasks(int numTasks, String ownerId) { + try(Connection conn = connectionFactory.getConnection(); + Statement statement = conn.createStatement()) + { + + /** + * First try to lock a row + */ + int counter = 0; + for(counter = 0; counter list = new ArrayList(); - list.add(row.getRowId()); - processUpdates(clazz.getName(), list); - updateReferences(clazz.getName()); + @SuppressWarnings("rawtypes") + private boolean processUpdateTable(UpdateTableRow row) throws Exception{ + Class clazz = getClassForTableName(row.getTableName()); + + // If there are any clients that have asked for all objects in a class then we have to push everything + if(accessManager.getNumClientsInterestedInWholeClass(clazz.getName()) > 0) { + processUpdates(getAllClassIdPairsForTable(row.getTableName())); + } + else { + processUpdates(clazz.getName(), accessManager.getClassAccessJournalIDs(clazz.getName())); + } + return true; } @@ -185,13 +228,36 @@ private void processUpdates(String className, Collection Ids) throws Exc for(String ID : Ids) { ClassIDPair pair = new ClassIDPair(ID, className); - IPerceroObject object = dataProvider.systemGetById(pair, true); - - if (object != null) { - cacheManager.updateCachedObject(object, null); - postPutHelper.postPutObject(pair, null, null, true, null); - } + handleUpdateClassIdPair(dataProvider, pair); } + + updateReferences(className); + } + + private void processUpdates(Set classIdPairs) throws Exception{ + Set classNamesToUpdateReferences = new HashSet(); + for(ClassIDPair classIdPair : classIdPairs) { + classNamesToUpdateReferences.add(classIdPair.getClassName()); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); + + handleUpdateClassIdPair(dataProvider, classIdPair); + } + + for(String className : classNamesToUpdateReferences) { + updateReferences(className); + } + } + + private void handleUpdateClassIdPair(IDataProvider dataProvider, ClassIDPair pair) throws Exception { + IPerceroObject object = dataProvider.findById(pair, null, true); + + if (object != null) { + cacheManager.updateCachedObject(object, null); + postPutHelper.postPutObject(pair, null, null, true, null); + } } /** @@ -199,95 +265,136 @@ private void processUpdates(String className, Collection Ids) throws Exc * @param row * @return */ - private boolean processInsertSingle(UpdateTableRow row) throws Exception{ + @SuppressWarnings("rawtypes") + private boolean processInsertSingle(UpdateTableRow row) throws Exception{ Class clazz = getClassForTableName(row.getTableName()); - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(clazz.getCanonicalName()); - IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - IPerceroObject perceroObject = dataProvider.systemGetById(new ClassIDPair(row.getRowId(), clazz.getCanonicalName()), true); - postCreateHelper.postCreateObject(perceroObject, null, null, true); + // We do not use PostCreateHelper here because we are going to do all + // that extra work for the whole class in updateReferences. + postPutHelper.postPutObject(new ClassIDPair(row.getRowId(), clazz.getCanonicalName()), null, null, true, null); updateReferences(clazz.getName()); return true; } /** - * process a whole table with deletes + * Process a whole table with inserts * @param row * @return */ - private boolean processDeleteTable(UpdateTableRow row) throws Exception{ - Class clazz = getClassForTableName(row.getTableName()); - Set accessedIds = accessManager.getClassAccessJournalIDs(clazz.getName()); - Set allIds = getAllIdsForTable(row.getTableName()); + private boolean processInsertTable(UpdateTableRow row) throws Exception { - // Now we have the set that has been removed that we care about - accessedIds.removeAll(allIds); - for(String id : accessedIds){ - postDeleteHelper.postDeleteObject(new ClassIDPair(id, clazz.getCanonicalName()), null, null, true); + MappedClass mappedClass = getMappedClassForTableName(row.getTableName()); + + // if any client needs all of this class then the only choice we have is to push everything + if(accessManager.getNumClientsInterestedInWholeClass(mappedClass.className) > 0 /* || true */){ + Set allClassIdPairs = getAllClassIdPairsForTable(row.getTableName()); + for(ClassIDPair classIdPair : allClassIdPairs) { + // We do not use PostCreateHelper here because we are going to + // do all that extra work for the whole class in + // updateReferences. + postPutHelper.postPutObject(classIdPair,null, null, true, null); + } } - updateReferences(clazz.getName()); + updateReferences(mappedClass.className); return true; } /** - * Process a whole table with updates + * Process a single record delete * @param row * @return */ - private boolean processUpdateTable(UpdateTableRow row) throws Exception{ + @SuppressWarnings("rawtypes") + private boolean processDeleteSingle(UpdateTableRow row) throws Exception{ Class clazz = getClassForTableName(row.getTableName()); + String className = clazz.getCanonicalName(); + + // See if this object is in the cache. If so, it will help us know which related objects to update. + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); + ClassIDPair pair = new ClassIDPair(row.getRowId(), className); + IPerceroObject cachedObject = dataProvider.findById(pair, null, false); // We are hoping to find this object in the cache... - Set accessedIds = null; - // If there are any clients that have asked for all objects in a class then we have to push everything - if(accessManager.getNumClientsInterestedInWholeClass(clazz.getName()) > 0) - accessedIds = getAllIdsForTable(row.getTableName()); - else - accessedIds = accessManager.getClassAccessJournalIDs(clazz.getName()); - - processUpdates(clazz.getName(), accessedIds); - updateReferences(clazz.getName()); - + handleDeletedObject(cachedObject, clazz, className, row.getRowId()); + + updateReferences(className); return true; } - private Set getAllIdsForTable(String tableName) throws SQLException{ - Set result = new HashSet(); - String query = "select ID from "+tableName; - try(Connection connection = connectionFactory.getConnection(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery(query)){ - - while(resultSet.next()){ - result.add(resultSet.getString("ID")); - } - } - - return result; - } - /** - * Process a whole table with inserts + * process a whole table with deletes * @param row * @return */ - private boolean processInsertTable(UpdateTableRow row) throws Exception { + @SuppressWarnings("rawtypes") + private boolean processDeleteTable(UpdateTableRow row) throws Exception{ + Class clazz = getClassForTableName(row.getTableName()); + String className = clazz.getCanonicalName(); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(clazz.getCanonicalName()); + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); + + // Get the list of ALL ID's of this class type that have been accessed. + Set accessedIds = accessManager.getClassAccessJournalIDs(clazz.getName()); + + // Get a list of ALL ID's of this class type. + Set allClassIdPairs = getAllClassIdPairsForTable(row.getTableName()); - MappedClass mappedClass = getMappedClassForTableName(row.getTableName()); + // Remove ALL existing/current ID's from our list of accessed ID's. + for(ClassIDPair nextClassIdPair : allClassIdPairs) { + accessedIds.remove(nextClassIdPair.getID()); + } - // if any client needs all of this class then the only choice we have is to push everything - if(accessManager.getNumClientsInterestedInWholeClass(mappedClass.className) > 0){ - Set allIds = getAllIdsForTable(row.getTableName()); - for(String id : allIds) - postPutHelper.postPutObject(new ClassIDPair(id, mappedClass.className), null, null, true, null); + // Now we have the list of ID's that have actually been deleted. + for(String id : accessedIds){ + // Find the cached object first so that it is NOT removed if the same object is NOT found in the data store. + IPerceroObject cachedObject = dataProvider.findById(new ClassIDPair(id, className), null, false); + // We will know an object has been deleted IFF it does NOT exist in the data store. + IPerceroObject dataStoreObject = dataProvider.findById(new ClassIDPair(id, className), null, true); + + if (dataStoreObject != null) { + // Object has NOT been deleted. + continue; + } + + handleDeletedObject(cachedObject, clazz, className, id); } - updateReferences(mappedClass.className); + updateReferences(clazz.getName()); return true; } + + @SuppressWarnings("rawtypes") + private void handleDeletedObject(IPerceroObject cachedObject, Class clazz, String className, String id) throws Exception { + boolean isShellObject = false; + if (cachedObject == null) { + cachedObject = (IPerceroObject) clazz.newInstance(); + cachedObject.setID(id); + isShellObject = true; + } + + cacheManager.handleDeletedObject(cachedObject, className, isShellObject); + + postDeleteHelper.postDeleteObject(new ClassIDPair(id, className), null, null, true); + } + + @SuppressWarnings("rawtypes") + private Set getAllClassIdPairsForTable(String tableName) throws Exception{ + Class clazz = getClassForTableName(tableName); + String className = clazz.getCanonicalName(); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); + Set results = dataProvider.getAllClassIdPairsByName(className); + + return results; + } private MappedClass getMappedClassForTableName(String tableName){ Class clazz = getClassForTableName(tableName); @@ -315,7 +422,53 @@ private void updateReferences(String className){ if (mappedField != null) { // Find all of this type and push down an update to all Set ids = accessManager.getClassAccessJournalIDs(mappedField.getMappedClass().className); - processUpdates(mappedField.getMappedClass().className, ids); + + if (ids.contains("0")) { + // If there is a 0 ID in the list, then we need to update ALL records of this type. + Integer pageNumber = 0; + Integer pageSize = 25; + Integer total = -1; + + while (total < 0 || pageNumber * pageSize <= total) { + PerceroList objectsToUpdate = mappedField.getMappedClass().getDataProvider().getAllByName(mappedField.getMappedClass().className, pageNumber, pageSize, true, null); + pageNumber++; + total = objectsToUpdate.getTotalLength(); + if (total <= 0) { + break; + } + + Iterator itrObjectsToUpdate = objectsToUpdate.iterator(); + while (itrObjectsToUpdate.hasNext()) { + IPerceroObject nextObjectToUpdate = itrObjectsToUpdate.next(); + ClassIDPair pair = BaseDataObject.toClassIdPair(nextObjectToUpdate); + Map> changedFields = new HashMap>(); + Collection changedMappedFields = new ArrayList(1); + changedMappedFields.add(mappedField); + changedFields.put(pair, changedMappedFields); + + // Remove from the cache. + cacheManager.deleteObjectFromCache(pair); + postPutHelper.postPutObject(pair, null, null, true, changedFields); + } + } + } + else { + Iterator itrIdsToUpdate = ids.iterator(); + while (itrIdsToUpdate.hasNext()) { + String nextIdToUpdate = itrIdsToUpdate.next(); + ClassIDPair pair = new ClassIDPair(nextIdToUpdate, mappedField.getMappedClass().className); + Map> changedFields = new HashMap>(); + Collection changedMappedFields = new ArrayList(1); + changedMappedFields.add(mappedField); + changedFields.put(pair, changedMappedFields); + + // Remove from the cache. + cacheManager.deleteObjectFromCache(pair); + postPutHelper.postPutObject(pair, null, null, true, changedFields); + } + } + +// processUpdates(mappedField.getMappedClass().className, ids); } } catch(Exception e) { logger.error("Error in postCreateObject " + mappedClass.className + "." + nextMappedField.getField().getName(), e); diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java index c691b7f..0bfb0d0 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessorFactory.java @@ -5,7 +5,6 @@ import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.cache.CacheManager; -import com.percero.agents.sync.helpers.PostCreateHelper; import com.percero.agents.sync.helpers.PostDeleteHelper; import com.percero.agents.sync.helpers.PostPutHelper; import com.percero.agents.sync.services.DataProviderManager; @@ -30,9 +29,6 @@ public class UpdateTableProcessorFactory { @Autowired PostPutHelper postPutHelper; - @Autowired - PostCreateHelper postCreateHelper; - @Autowired CacheManager cacheManager; @@ -44,6 +40,6 @@ public class UpdateTableProcessorFactory { public UpdateTableProcessor getProcessor(String tableName){ return new UpdateTableProcessor(tableName, connectionFactory, manifest, - postDeleteHelper, postPutHelper, postCreateHelper, cacheManager, dataProviderManager, accessManager); + postDeleteHelper, postPutHelper, cacheManager, dataProviderManager, accessManager); } } diff --git a/src/main/java/com/percero/agents/sync/metadata/MappedClass.java b/src/main/java/com/percero/agents/sync/metadata/MappedClass.java index 2a8e865..c8c23c4 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedClass.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedClass.java @@ -49,6 +49,8 @@ import com.percero.agents.sync.metadata.annotations.RelationshipInterfaces; import com.percero.agents.sync.services.DataProviderManager; import com.percero.agents.sync.services.IDataProvider; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.agents.sync.vo.ClassIDPair; import com.percero.framework.bl.IManifest; import com.percero.framework.bl.ManifestHelper; import com.percero.framework.metadata.IMappedClass; @@ -1243,6 +1245,132 @@ else if ((this.className == null || this.className.trim().length() == 0) || (mcO } } + + + + /*************************************** + * Helper Methods + ***************************************/ + public Map getRelatedClassIdPairMappedFieldMap(IPerceroObject perceroObject, Boolean isShellObject) throws Exception { + Map results = new HashMap(); + + Iterator itrToOneFieldsToUpdate = toOneFields.iterator(); + while (itrToOneFieldsToUpdate.hasNext()) { + MappedFieldPerceroObject nextToOneField = itrToOneFieldsToUpdate.next(); + + // If no reverse mapped field, then nothing to do. + if (nextToOneField.getReverseMappedField() != null) { + + // If no PerceroObject, then we need to retrieve ALL objects of this type. + if (perceroObject == null) { + MappedClass reverseMappedClass = nextToOneField.getReverseMappedField().getMappedClass(); + IDataProvider reverseDataProvider = reverseMappedClass.getDataProvider(); + List relatedObjects = reverseDataProvider.getAllByName(reverseMappedClass.className, null, null, false, null); + Iterator itrRelatedObjects = relatedObjects.iterator(); + while (itrRelatedObjects.hasNext()) { + IPerceroObject nextRelatedObject = itrRelatedObjects.next(); + results.put(BaseDataObject.toClassIdPair(nextRelatedObject), nextToOneField.getReverseMappedField()); + } + } + else if (isShellObject) { + // If this is a Shell Object, then we need to ask the IDataProvider to get the related objects. + List relatedObjects = getDataProvider().findAllRelatedObjects(perceroObject, nextToOneField, true, null); + Iterator itrRelatedObjects = relatedObjects.iterator(); + while (itrRelatedObjects.hasNext()) { + IPerceroObject nextRelatedObject = itrRelatedObjects.next(); + results.put(BaseDataObject.toClassIdPair(nextRelatedObject), nextToOneField.getReverseMappedField()); + } + } + else { + IPerceroObject toOneObject = (IPerceroObject) nextToOneField.getGetter().invoke(perceroObject); + if (toOneObject != null) { + results.put(BaseDataObject.toClassIdPair(toOneObject), nextToOneField.getReverseMappedField()); + } + } + } + } + + Iterator itrToManyFieldsToUpdate = toManyFields.iterator(); + while (itrToManyFieldsToUpdate.hasNext()) { + MappedField nextToManyField = itrToManyFieldsToUpdate.next(); + if (nextToManyField instanceof MappedFieldPerceroObject) { + MappedFieldPerceroObject nextPerceroObjectField = (MappedFieldPerceroObject) nextToManyField; + + if (nextPerceroObjectField.getReverseMappedField() != null) { + + // If no PerceroObject, then we need to retrieve ALL objects of this type. + if (perceroObject == null) { + MappedClass reverseMappedClass = nextToManyField.getReverseMappedField().getMappedClass(); + IDataProvider reverseDataProvider = reverseMappedClass.getDataProvider(); + List relatedObjects = reverseDataProvider.getAllByName(reverseMappedClass.className, null, null, false, null); + Iterator itrRelatedObjects = relatedObjects.iterator(); + while (itrRelatedObjects.hasNext()) { + IPerceroObject nextRelatedObject = itrRelatedObjects.next(); + results.put(BaseDataObject.toClassIdPair(nextRelatedObject), nextToManyField.getReverseMappedField()); + } + } + else if (isShellObject) { + // If this is a Shell Object, then we need to ask the IDataProvider to get the related objects. + List relatedObjects = getDataProvider().findAllRelatedObjects(perceroObject, nextToManyField, true, null); + Iterator itrRelatedObjects = relatedObjects.iterator(); + while (itrRelatedObjects.hasNext()) { + IPerceroObject nextRelatedObject = itrRelatedObjects.next(); + results.put(BaseDataObject.toClassIdPair(nextRelatedObject), nextToManyField.getReverseMappedField()); + } + } + else { + IPerceroObject toOneObject = (IPerceroObject) nextPerceroObjectField.getGetter().invoke(perceroObject); + if (toOneObject != null) { + results.put(BaseDataObject.toClassIdPair(toOneObject), nextPerceroObjectField.getReverseMappedField()); + } + } + } + } + else if (nextToManyField instanceof MappedFieldList) { + MappedFieldList nextListField = (MappedFieldList) nextToManyField; + + if (nextListField.getReverseMappedField() != null) { + + // If no PerceroObject, then we need to retrieve ALL objects of this type. + if (perceroObject == null) { + MappedClass reverseMappedClass = nextToManyField.getReverseMappedField().getMappedClass(); + IDataProvider reverseDataProvider = reverseMappedClass.getDataProvider(); + List relatedObjects = reverseDataProvider.getAllByName(reverseMappedClass.className, null, null, false, null); + Iterator itrRelatedObjects = relatedObjects.iterator(); + while (itrRelatedObjects.hasNext()) { + IPerceroObject nextRelatedObject = itrRelatedObjects.next(); + results.put(BaseDataObject.toClassIdPair(nextRelatedObject), nextToManyField.getReverseMappedField()); + } + } + else if (isShellObject) { + // If this is a Shell Object, then we need to ask the IDataProvider to get the related objects. + List relatedObjects = getDataProvider().findAllRelatedObjects(perceroObject, nextToManyField, true, null); + Iterator itrRelatedObjects = relatedObjects.iterator(); + while (itrRelatedObjects.hasNext()) { + IPerceroObject nextRelatedObject = itrRelatedObjects.next(); + results.put(BaseDataObject.toClassIdPair(nextRelatedObject), nextToManyField.getReverseMappedField()); + } + } + else { + List listObjects = (List) nextListField.getGetter().invoke(perceroObject); + if (listObjects != null && !listObjects.isEmpty()) { + Iterator itrListObjects = listObjects.iterator(); + while (itrListObjects.hasNext()) { + IPerceroObject nextListObject = itrListObjects.next(); + results.put(BaseDataObject.toClassIdPair(nextListObject), nextListField.getReverseMappedField()); + } + } + } + } + } + } + + return results; + } + + + + /*************************************** * Static Helper Methods ***************************************/ @@ -1296,4 +1424,6 @@ public MappedClassMethodPair(MappedClass mappedClass, Method method) { } } + + } diff --git a/src/main/java/com/percero/agents/sync/services/DAODataProvider.java b/src/main/java/com/percero/agents/sync/services/DAODataProvider.java index d5ad6f3..fe25bb5 100644 --- a/src/main/java/com/percero/agents/sync/services/DAODataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/DAODataProvider.java @@ -130,6 +130,24 @@ public PerceroList getAllByName(String className, Integer pageNu return results; } + @SuppressWarnings("unchecked") + public Set getAllClassIdPairsByName(String className) throws Exception { + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(className); + PerceroList allObjects = dao.getAll(null, null, false, null, true); + + Set results = new HashSet(allObjects == null ? 0 : allObjects.size()); + + if (allObjects != null && !allObjects.isEmpty()) { + Iterator itrResults = allObjects.iterator(); + while (itrResults.hasNext()) { + IPerceroObject nextResult = itrResults.next(); + results.add(BaseDataObject.toClassIdPair(nextResult)); + } + } + + return results; + } + @SuppressWarnings({ "unchecked" }) // TODO: @Transactional(readOnly=true) public Integer countAllByName(String className, String userId) throws Exception { @@ -223,11 +241,17 @@ protected static List processQueryResults(String resultClassName, Query return results; } - @SuppressWarnings("unchecked") public IPerceroObject findById(ClassIDPair classIdPair, String userId) { + return findById(classIdPair, userId, false); + } + @SuppressWarnings("unchecked") + public IPerceroObject findById(ClassIDPair classIdPair, String userId, Boolean ignoreCache) { try { - IPerceroObject result = retrieveFromRedisCache(classIdPair); + IPerceroObject result = null; + if (!ignoreCache) { + result = retrieveFromRedisCache(classIdPair); + } if (result == null) { @@ -420,8 +444,11 @@ public Boolean getDeleteAccess(ClassIDPair classIdPair, String userId) { return dao.hasDeleteAccess(classIdPair, userId); } - @SuppressWarnings({ }) public List findByIds(ClassIDPairs classIdPairs, String userId) { + return findByIds(classIdPairs, userId, false); + } + @SuppressWarnings({ }) + public List findByIds(ClassIDPairs classIdPairs, String userId, Boolean ignoreCache) { IDataAccessObject dao = DAORegistry.getInstance().getDataAccessObject(classIdPairs.getClassName()); List results = new ArrayList(); @@ -434,17 +461,20 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) idsToFind.addAll(classIdPairs.getIds()); classIdPairsCopy.setIds(idsToFind); - Map cachedResults = retrieveFromRedisCache(classIdPairs, true); - if (cachedResults != null &&!cachedResults.isEmpty()) { - // Add the cached results - - Iterator itrCachedResults = cachedResults.values().iterator(); - while (itrCachedResults.hasNext()) { - IPerceroObject nextCachedResult = itrCachedResults.next(); - if (nextCachedResult != null) { - idsToFind.remove(nextCachedResult.getID()); - results.add(nextCachedResult); - setObjectExpiration(nextCachedResult); + Map cachedResults = null; + if (!ignoreCache) { + cachedResults = retrieveFromRedisCache(classIdPairs, true); + if (cachedResults != null &&!cachedResults.isEmpty()) { + // Add the cached results + + Iterator itrCachedResults = cachedResults.values().iterator(); + while (itrCachedResults.hasNext()) { + IPerceroObject nextCachedResult = itrCachedResults.next(); + if (nextCachedResult != null) { + idsToFind.remove(nextCachedResult.getID()); + results.add(nextCachedResult); + setObjectExpiration(nextCachedResult); + } } } } @@ -1033,6 +1063,7 @@ private Collection retrieveObjectsNotInCollection(Collection baseList, Collectio */ // @Override + @SuppressWarnings("unchecked") public List findAllRelatedObjects(IPerceroObject perceroObject, MappedField mappedField, Boolean shellOnly, String userId) throws SyncException { List result = new ArrayList(); @@ -1040,24 +1071,66 @@ public List findAllRelatedObjects(IPerceroObject perceroObject, // No valid ID on the object, so can't search for it. return result; } - - // The reverse mapped field should be the MappedField on the target object, the one that this MUST be the data provider for. - MappedField reverseMappedField = mappedField.getReverseMappedField(); - if (reverseMappedField == null) { - // No reverse mapped field, meaning there is nothing to do. - return result; + + if (mappedField.getMappedClass().getSourceMappedFields().contains(mappedField)) { + // This object is the source. + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(mappedField.getMappedClass().className); + IPerceroObject thisObject = dao.retrieveObject(BaseDataObject.toClassIdPair(perceroObject), userId, false); + IPerceroObject relatedObject; + try { + relatedObject = (IPerceroObject) mappedField.getGetter().invoke(thisObject); + } catch (Exception e) { + throw new SyncException(e); + } + if (relatedObject != null) { + if (!shellOnly) { + MappedClass relatedMappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(relatedObject.getClass().getCanonicalName()); + relatedObject = relatedMappedClass.getDataProvider().findById(BaseDataObject.toClassIdPair(relatedObject), userId); + } + result.add(relatedObject); + } + result.add(relatedObject); + } + else { + // This object is the target. + // The reverse mapped field should be the MappedField on the target object, the one that this MUST be the data provider for. + MappedField reverseMappedField = mappedField.getReverseMappedField(); + if (reverseMappedField == null) { + // No reverse mapped field, meaning there is nothing to do. + return result; + } + + IDataProvider dataProvider = reverseMappedField.getMappedClass().getDataProvider(); + result = dataProvider.getAllByRelationship(reverseMappedField, BaseDataObject.toClassIdPair(perceroObject), shellOnly, userId); } - - IDataProvider dataProvider = dataProviderManager.getDataProviderByName(reverseMappedField.getMappedClass().dataProviderName); - result = dataProvider.getAllByRelationship(reverseMappedField, BaseDataObject.toClassIdPair(perceroObject), shellOnly, userId); return result; } @SuppressWarnings("unchecked") public List getAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException { - IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(mappedField.getMappedClass().className); - return dao.retrieveAllByRelationship(mappedField, targetClassIdPair, shellOnly, userId); + if (mappedField.getMappedClass().getSourceMappedFields().contains(mappedField)) { + // This object is the source. + IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(mappedField.getMappedClass().className); + return dao.retrieveAllByRelationship(mappedField, targetClassIdPair, shellOnly, userId); + } + else { + // This object is the target. + if (mappedField.getReverseMappedField() != null) { + IDataProvider dataProvider = mappedField.getReverseMappedField().getMappedClass().getDataProvider(); + try { + IPerceroObject targetObject = (IPerceroObject) Class.forName(targetClassIdPair.getClassName()).newInstance(); + return dataProvider.findAllRelatedObjects(targetObject, mappedField.getReverseMappedField(), shellOnly, userId); + } catch(Exception e) { + throw new SyncException(e); + } + } + else { + return new ArrayList(0); + } + } + + } diff --git a/src/main/java/com/percero/agents/sync/services/DataProviderManager.java b/src/main/java/com/percero/agents/sync/services/DataProviderManager.java index b6ee68e..9165e3c 100644 --- a/src/main/java/com/percero/agents/sync/services/DataProviderManager.java +++ b/src/main/java/com/percero/agents/sync/services/DataProviderManager.java @@ -47,10 +47,15 @@ public IDataProvider getDataProviderByName(String aName) { if (!dataProvidersByName.containsKey(aName)) { // Attempt to get the bean from the ApplicationContext. - IDataProvider dataProvider = (IDataProvider) appContext.getBean(aName); - dataProvider.initialize(); - addDataProvider(dataProvider); - return dataProvider; + try { + IDataProvider dataProvider = (IDataProvider) appContext.getBean(aName); + dataProvider.initialize(); + addDataProvider(dataProvider); + return dataProvider; + } catch(Exception e) { + // If no data provider is found, then assume the default. + return defaultDataProvider; + } } else return dataProvidersByName.get(aName); } diff --git a/src/main/java/com/percero/agents/sync/services/IDataProvider.java b/src/main/java/com/percero/agents/sync/services/IDataProvider.java index e9fd277..dc40989 100644 --- a/src/main/java/com/percero/agents/sync/services/IDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/IDataProvider.java @@ -3,6 +3,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import com.percero.agents.sync.exceptions.SyncException; import com.percero.agents.sync.metadata.MappedClass; @@ -20,8 +21,11 @@ public interface IDataProvider { public Integer countAllByName(String className, String userId) throws Exception; public PerceroList getAllByName(String className, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception; + public Set getAllClassIdPairsByName(String className) throws Exception; public List runQuery(MappedClass mappedClass, String queryName, Object[] queryArguments, String clientId) throws SyncException; + public IPerceroObject findById(ClassIDPair classIdPair, String userId); public IPerceroObject findById(ClassIDPair classIdPair, String userId, Boolean ignoreCache); + public List findByIds(ClassIDPairs classIdPairs, String userId); public List findByIds(ClassIDPairs classIdPairs, String userId, Boolean ignoreCache); // public IPerceroObject findUnique(IPerceroObject theQueryObject, String userId); public List findByExample(IPerceroObject theQueryObject, List excludeProperties, String userId, Boolean shellOnly) throws SyncException; diff --git a/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java b/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java index 643843d..0922ba2 100644 --- a/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java @@ -3,6 +3,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import org.hibernate.Session; import org.springframework.stereotype.Component; @@ -411,4 +412,18 @@ public List cleanObject( // TODO Auto-generated method stub return null; } + + @Override + public Set getAllClassIdPairsByName(String className) + throws Exception { + // TODO Auto-generated method stub + return null; + } + + @Override + public List findByIds(ClassIDPairs classIdPairs, + String userId) { + // TODO Auto-generated method stub + return null; + } } diff --git a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java b/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java index 1fd5531..316d351 100644 --- a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java @@ -1,6 +1,5 @@ package com.percero.agents.sync.services; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; @@ -1589,40 +1588,75 @@ private Collection retrieveObjectsNotInCollection(Collection baseList, Collectio } - public List getAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException { -// throw new SyncException(SyncException.METHOD_UNSUPPORTED, SyncException.METHOD_UNSUPPORTED_CODE); - try { - IPerceroObject exampleObject = (IPerceroObject) mappedField.getMappedClass().clazz.newInstance(); - IPerceroObject targetObject = (IPerceroObject) Class.forName(targetClassIdPair.getClassName()).newInstance(); - targetObject.setID(targetClassIdPair.getID()); - mappedField.getSetter().invoke(exampleObject, targetObject); - return findByExample(exampleObject, null, userId, shellOnly); - } catch (InstantiationException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ClassNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - return null; - - } - @Override public List findAllRelatedObjects( IPerceroObject perceroObject, MappedField mappedField, Boolean shellOnly, String userId) throws SyncException { - throw new SyncException(SyncException.METHOD_UNSUPPORTED, SyncException.METHOD_UNSUPPORTED_CODE); + List result = new ArrayList(); + + if (!StringUtils.hasText(perceroObject.getID())) { + // No valid ID on the object, so can't search for it. + return result; + } + + if (mappedField.getMappedClass().getSourceMappedFields().contains(mappedField)) { + // This object is the source. + IPerceroObject thisObject = this.findById(BaseDataObject.toClassIdPair(perceroObject), userId); + IPerceroObject relatedObject; + try { + relatedObject = (IPerceroObject) mappedField.getGetter().invoke(thisObject); + } catch (Exception e) { + throw new SyncException(e); + } + if (relatedObject != null) { + if (!shellOnly) { + MappedClass relatedMappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(relatedObject.getClass().getCanonicalName()); + relatedObject = relatedMappedClass.getDataProvider().findById(BaseDataObject.toClassIdPair(relatedObject), userId); + } + result.add(relatedObject); + } + } + else { + // This object is the target. + // The reverse mapped field should be the MappedField on the target object, the one that this MUST be the data provider for. + MappedField reverseMappedField = mappedField.getReverseMappedField(); + if (reverseMappedField == null) { + // No reverse mapped field, meaning there is nothing to do. + return result; + } + + IDataProvider dataProvider = reverseMappedField.getMappedClass().getDataProvider(); + result = dataProvider.getAllByRelationship(reverseMappedField, BaseDataObject.toClassIdPair(perceroObject), shellOnly, userId); + } + + return result; + } + + public List getAllByRelationship(MappedField mappedField, ClassIDPair targetClassIdPair, Boolean shellOnly, String userId) throws SyncException { +// throw new SyncException(SyncException.METHOD_UNSUPPORTED, SyncException.METHOD_UNSUPPORTED_CODE); + try { + if (mappedField.getMappedClass().getSourceMappedFields().contains(mappedField)) { + // This object is the source. + IPerceroObject exampleObject = (IPerceroObject) mappedField.getMappedClass().clazz.newInstance(); + IPerceroObject targetObject = (IPerceroObject) Class.forName(targetClassIdPair.getClassName()).newInstance(); + targetObject.setID(targetClassIdPair.getID()); + mappedField.getSetter().invoke(exampleObject, targetObject); + return findByExample(exampleObject, null, userId, shellOnly); + } + else { + // This object is the target. + if (mappedField.getReverseMappedField() != null) { + IDataProvider dataProvider = mappedField.getReverseMappedField().getMappedClass().getDataProvider(); + IPerceroObject targetObject = (IPerceroObject) Class.forName(targetClassIdPair.getClassName()).newInstance(); + return dataProvider.findAllRelatedObjects(targetObject, mappedField.getReverseMappedField(), shellOnly, userId); + } + else { + return new ArrayList(0); + } + } + } catch (Exception e) { + throw new SyncException(e); + } } @Override diff --git a/src/main/java/com/percero/agents/sync/services/SyncAgentService.java b/src/main/java/com/percero/agents/sync/services/SyncAgentService.java index 34dff38..b7f20a9 100644 --- a/src/main/java/com/percero/agents/sync/services/SyncAgentService.java +++ b/src/main/java/com/percero/agents/sync/services/SyncAgentService.java @@ -12,6 +12,8 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import java.util.UUID; import javax.annotation.PostConstruct; @@ -1094,16 +1096,12 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, MappedField nextRemoveMappedFieldRef = nextEntry.getKey(); try { MappedField nextMappedField = nextEntry.getValue(); -// for(MappedField nextRemoveMappedFieldRef : mappedClass.cascadeRemoveFieldReferences.keySet()) { -// try { -// // nextRemoveMappedFieldRef points to mappedClass, so need to find all objects of that type that point to this particular -// // instance perceroObejct of mappedClass. -// MappedField nextMappedField = mappedClass.cascadeRemoveFieldReferences.get(nextRemoveMappedFieldRef); if (nextMappedField == null) { // There is no direct link from mappedClass, so need to get all by example. IPerceroObject tempObject = (IPerceroObject) nextRemoveMappedFieldRef.getMappedClass().clazz.newInstance(); nextRemoveMappedFieldRef.getSetter().invoke(tempObject, perceroObject); IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextRemoveMappedFieldRef.getMappedClass().dataProviderName); + List referencingObjectsNew = dataProviderRef.findAllRelatedObjects(perceroObject, nextMappedField, false, null); List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); Iterator itrReferencingObjects = referencingObjects.iterator(); while (itrReferencingObjects.hasNext()) { @@ -1116,6 +1114,7 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, IPerceroObject tempObject = (IPerceroObject) nextRemoveMappedFieldRef.getMappedClass().clazz.newInstance(); nextRemoveMappedFieldRef.getSetter().invoke(tempObject, perceroObject); IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextRemoveMappedFieldRef.getMappedClass().dataProviderName); + List referencingObjectsNew = dataProviderRef.findAllRelatedObjects(perceroObject, nextMappedField, false, null); List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); Iterator itrReferencingObjects = referencingObjects.iterator(); while (itrReferencingObjects.hasNext()) { @@ -1137,16 +1136,12 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, MappedField nextToNullMappedFieldRef = nextEntry.getKey(); try { MappedField nextMappedField = nextEntry.getValue(); -// for(MappedField nextToNullMappedFieldRef : mappedClass.nulledOnRemoveFieldReferences.keySet()) { -// try { -// // nextRemoveMappedFieldRef points to mappedClass, so need to find all objects of that type that point to this particular -// // instance perceroObejct of mappedClass. -// MappedField nextMappedField = mappedClass.nulledOnRemoveFieldReferences.get(nextToNullMappedFieldRef); if (nextMappedField == null) { // There is no direct link from mappedClass, so need to get all by example. IPerceroObject tempObject = (IPerceroObject) nextToNullMappedFieldRef.getMappedClass().clazz.newInstance(); nextToNullMappedFieldRef.getSetter().invoke(tempObject, perceroObject); IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextToNullMappedFieldRef.getMappedClass().dataProviderName); + List referencingObjectsNew = dataProviderRef.findAllRelatedObjects(perceroObject, nextMappedField, false, null); List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); Iterator itrReferencingObjects = referencingObjects.iterator(); while (itrReferencingObjects.hasNext()) { @@ -1160,6 +1155,7 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, IPerceroObject tempObject = (IPerceroObject) nextToNullMappedFieldRef.getMappedClass().clazz.newInstance(); nextToNullMappedFieldRef.getSetter().invoke(tempObject, perceroObject); IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextToNullMappedFieldRef.getMappedClass().dataProviderName); + List referencingObjectsNew = dataProviderRef.findAllRelatedObjects(perceroObject, nextMappedField, false, null); List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); Iterator itrReferencingObjects = referencingObjects.iterator(); while (itrReferencingObjects.hasNext()) { @@ -1174,31 +1170,7 @@ public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, } } - Iterator itrToOneFieldsToUpdate = mappedClass.toOneFields.iterator(); - while (itrToOneFieldsToUpdate.hasNext()) { - MappedFieldPerceroObject nextToOneField = itrToOneFieldsToUpdate.next(); - if (nextToOneField instanceof MappedFieldPerceroObject) { - MappedFieldPerceroObject nextPerceroObjectField = (MappedFieldPerceroObject) nextToOneField; - IPerceroObject toOneObject = (IPerceroObject) nextPerceroObjectField.getGetter().invoke(perceroObject); - if (toOneObject != null) { - // Remove this object from the cache. - // TODO: ? - } - } - } - - Iterator itrToManyFieldsToUpdate = mappedClass.toManyFields.iterator(); - while (itrToManyFieldsToUpdate.hasNext()) { - MappedField nextToManyField = itrToManyFieldsToUpdate.next(); - if (nextToManyField instanceof MappedFieldPerceroObject) { - MappedFieldPerceroObject nextPerceroObjectField = (MappedFieldPerceroObject) nextToManyField; - // TODO: ? - } - else if (nextToManyField instanceof MappedFieldList) { - MappedFieldList nextListField = (MappedFieldList) nextToManyField; - // TODO: ? - } - } + Map objectsToUpdate = mappedClass.getRelatedClassIdPairMappedFieldMap(perceroObject, false); // If the result has been set to false, it means that deletion/update of one of the related objects failed. if (result && dataProvider.deleteObject(BaseDataObject.toClassIdPair(perceroObject), null)) { @@ -1227,6 +1199,16 @@ else if (nextToManyField instanceof MappedFieldList) { postDeleteHelper.postDeleteObject(perceroObject, userId, clientId, pushToUser); } + Iterator> itrObjectsToUpdate = objectsToUpdate.entrySet().iterator(); + while (itrObjectsToUpdate.hasNext()) { + Entry nextObjectToUpdate = itrObjectsToUpdate.next(); + Map> changedFields = new HashMap>(); + Collection changedMappedFields = new ArrayList(1); + changedMappedFields.add(nextObjectToUpdate.getValue()); + changedFields.put(nextObjectToUpdate.getKey(), changedMappedFields); + postPutHelper.postPutObject(nextObjectToUpdate.getKey(), userId, clientId, true, changedFields); + } + result = true; } else { @@ -1236,6 +1218,7 @@ else if (nextToManyField instanceof MappedFieldList) { return result; } + public void updatesReceived(ClassIDPair[] theObjects, String clientId) throws Exception { Boolean isValidClient = accessManager.validateClientByClientId(clientId); From 5c2269d732a4c1ad1d67e12660d5225824e9cf1d Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Thu, 17 Sep 2015 14:48:00 -0700 Subject: [PATCH 19/20] wip --- .../percero/agents/sync/jobs/UpdateTableProcessor.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java index e6288e6..f4e8678 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java @@ -21,7 +21,6 @@ import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.cache.CacheManager; -import com.percero.agents.sync.helpers.PostCreateHelper; import com.percero.agents.sync.helpers.PostDeleteHelper; import com.percero.agents.sync.helpers.PostPutHelper; import com.percero.agents.sync.metadata.IMappedClassManager; @@ -73,11 +72,16 @@ public UpdateTableProcessor(String tableName, this.dataProviderManager= dataProviderManager; this.accessManager = accessManager; - insertTasks(100, "9"); + insertTasks(1000, "9"); } + private static Boolean tasksInserted = false; + private void insertTasks(int numTasks, String ownerId) { + if (tasksInserted) { + return; + } try(Connection conn = connectionFactory.getConnection(); Statement statement = conn.createStatement()) { @@ -94,6 +98,8 @@ private void insertTasks(int numTasks, String ownerId) { int numUpdated = statement.executeUpdate(sql); } + + tasksInserted = true; } catch(SQLException e){ logger.warn(e.getMessage(), e); From f71c7011ed4b1254ec9fa57776879371d4e14b2b Mon Sep 17 00:00:00 2001 From: Collin Brown Date: Thu, 17 Sep 2015 15:37:30 -0700 Subject: [PATCH 20/20] Wrapping up work for UpdateTable --- .../sync/access/RedisAccessManager.java | 3 +- .../agents/sync/jobs/UpdateTablePoller.java | 6 +- .../sync/jobs/UpdateTableProcessor.java | 136 ++++++++---------- 3 files changed, 61 insertions(+), 84 deletions(-) diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index db44c71..c392dec 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -898,7 +898,8 @@ public List getObjectAccessJournals(String className, String classId) th return result; } - public Set getClassAccessJournalIDs(String className){ + @SuppressWarnings("unchecked") + public Set getClassAccessJournalIDs(String className){ return (Set) cacheDataStore.getSetValue(RedisKeyUtils.classAccessJournal(className)); } diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java index bdd4ea4..323452e 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java @@ -1,10 +1,6 @@ package com.percero.agents.sync.jobs; -import com.mchange.v2.c3p0.ComboPooledDataSource; -import com.percero.agents.sync.helpers.PostDeleteHelper; -import com.percero.framework.bl.IManifest; import org.apache.log4j.Logger; -import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; @@ -33,7 +29,7 @@ public void setTableNames(String val){ /** * Run every minute */ - @Scheduled(fixedDelay=10000, initialDelay=10000) + @Scheduled(fixedDelay=5000, initialDelay=10000) // Every 5 seconds public void pollUpdateTables(){ if(enabled) for(String tableName : tableNames){ diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java index f4e8678..b13745e 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java @@ -12,7 +12,6 @@ import java.util.Map; import java.util.Random; import java.util.Set; -import java.util.UUID; import javax.persistence.Table; @@ -71,40 +70,8 @@ public UpdateTableProcessor(String tableName, this.cacheManager = cacheManager; this.dataProviderManager= dataProviderManager; this.accessManager = accessManager; - - insertTasks(1000, "9"); } - private static Boolean tasksInserted = false; - - - private void insertTasks(int numTasks, String ownerId) { - if (tasksInserted) { - return; - } - try(Connection conn = connectionFactory.getConnection(); - Statement statement = conn.createStatement()) - { - - /** - * First try to lock a row - */ - int counter = 0; - for(counter = 0; counter 0) { - processUpdates(getAllClassIdPairsForTable(row.getTableName())); + if(accessManager.getNumClientsInterestedInWholeClass(className) > 0) { + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); + + Integer pageNumber = 0; + Integer pageSize = 25; + Integer total = -1; + + while (total < 0 || pageNumber * pageSize <= total) { + PerceroList objectsToUpdate = dataProvider.getAllByName(className, pageNumber, pageSize, true, null); + pageNumber++; + total = objectsToUpdate.getTotalLength(); + if (total <= 0) { + break; + } + + Set objectIds = new HashSet(objectsToUpdate.size()); + Iterator itrObjectsToUpdate = objectsToUpdate.iterator(); + while (itrObjectsToUpdate.hasNext()) { + IPerceroObject nextObjectToUpdate = itrObjectsToUpdate.next(); + objectIds.add(nextObjectToUpdate.getID()); + } + + processUpdates(className, objectIds); + } } else { - processUpdates(clazz.getName(), accessManager.getClassAccessJournalIDs(clazz.getName())); + processUpdates(className, accessManager.getClassAccessJournalIDs(className)); } + updateReferences(className); + return true; } @@ -236,25 +234,6 @@ private void processUpdates(String className, Collection Ids) throws Exc ClassIDPair pair = new ClassIDPair(ID, className); handleUpdateClassIdPair(dataProvider, pair); } - - updateReferences(className); - } - - private void processUpdates(Set classIdPairs) throws Exception{ - Set classNamesToUpdateReferences = new HashSet(); - for(ClassIDPair classIdPair : classIdPairs) { - classNamesToUpdateReferences.add(classIdPair.getClassName()); - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); - IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - - handleUpdateClassIdPair(dataProvider, classIdPair); - } - - for(String className : classNamesToUpdateReferences) { - updateReferences(className); - } } private void handleUpdateClassIdPair(IDataProvider dataProvider, ClassIDPair pair) throws Exception { @@ -274,11 +253,13 @@ private void handleUpdateClassIdPair(IDataProvider dataProvider, ClassIDPair pai @SuppressWarnings("rawtypes") private boolean processInsertSingle(UpdateTableRow row) throws Exception{ Class clazz = getClassForTableName(row.getTableName()); + String className = clazz.getCanonicalName(); // We do not use PostCreateHelper here because we are going to do all // that extra work for the whole class in updateReferences. - postPutHelper.postPutObject(new ClassIDPair(row.getRowId(), clazz.getCanonicalName()), null, null, true, null); - updateReferences(clazz.getName()); + postPutHelper.postPutObject(new ClassIDPair(row.getRowId(), className), null, null, true, null); + + updateReferences(className); return true; } @@ -287,12 +268,13 @@ private boolean processInsertSingle(UpdateTableRow row) throws Exception{ * @param row * @return */ - private boolean processInsertTable(UpdateTableRow row) throws Exception { - - MappedClass mappedClass = getMappedClassForTableName(row.getTableName()); + @SuppressWarnings("rawtypes") + private boolean processInsertTable(UpdateTableRow row) throws Exception { + Class clazz = getClassForTableName(row.getTableName()); + String className = clazz.getCanonicalName(); // if any client needs all of this class then the only choice we have is to push everything - if(accessManager.getNumClientsInterestedInWholeClass(mappedClass.className) > 0 /* || true */){ + if(accessManager.getNumClientsInterestedInWholeClass(className) > 0 /* || true */){ Set allClassIdPairs = getAllClassIdPairsForTable(row.getTableName()); for(ClassIDPair classIdPair : allClassIdPairs) { // We do not use PostCreateHelper here because we are going to @@ -302,7 +284,7 @@ private boolean processInsertTable(UpdateTableRow row) throws Exception { } } - updateReferences(mappedClass.className); + updateReferences(className); return true; } @@ -341,11 +323,14 @@ private boolean processDeleteTable(UpdateTableRow row) throws Exception{ String className = clazz.getCanonicalName(); IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(clazz.getCanonicalName()); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); // Get the list of ALL ID's of this class type that have been accessed. - Set accessedIds = accessManager.getClassAccessJournalIDs(clazz.getName()); + Set accessedIds = accessManager.getClassAccessJournalIDs(className); + + // TODO: If ID "0", then that means someone wants to know about ALL + // records of this type. How do we do this? // Get a list of ALL ID's of this class type. Set allClassIdPairs = getAllClassIdPairsForTable(row.getTableName()); @@ -370,7 +355,7 @@ private boolean processDeleteTable(UpdateTableRow row) throws Exception{ handleDeletedObject(cachedObject, clazz, className, id); } - updateReferences(clazz.getName()); + updateReferences(className); return true; } @@ -402,12 +387,6 @@ private Set getAllClassIdPairsForTable(String tableName) throws Exc return results; } - private MappedClass getMappedClassForTableName(String tableName){ - Class clazz = getClassForTableName(tableName); - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(clazz.getName()); - return mappedClass; - } /** * Finds all back references to this class and pushes updates to all of them. @@ -416,11 +395,13 @@ private MappedClass getMappedClassForTableName(String tableName){ private void updateReferences(String className){ IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(className); - // Go through each mapped field and push all objects of that associated type (just in case any has a reference to a new row - // in the updated table) + // Go through each mapped field and push all objects of that associated + // type (just in case any has a reference to a new row + // in the updated table) // -- - // TODO: is this right? Is it enough to only check the relationships on this class or do we need to look - // through all of the mapped classes? + // TODO: is this right? Is it enough to only check the relationships on + // this class or do we need to look + // through all of the mapped classes? for(MappedFieldPerceroObject nextMappedField : mappedClass.externalizablePerceroObjectFields) { try { // Only care about it if it has a reverse relationship @@ -473,8 +454,6 @@ private void updateReferences(String className){ postPutHelper.postPutObject(pair, null, null, true, changedFields); } } - -// processUpdates(mappedField.getMappedClass().className, ids); } } catch(Exception e) { logger.error("Error in postCreateObject " + mappedClass.className + "." + nextMappedField.getField().getName(), e); @@ -555,7 +534,8 @@ private void deleteRow(UpdateTableRow row){ } } - public Class getClassForTableName(String tableName){ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Class getClassForTableName(String tableName){ Class result = null; // First look for the @Table annotation