diff --git a/API.md b/API.md new file mode 100644 index 0000000..2e7b21d --- /dev/null +++ b/API.md @@ -0,0 +1,171 @@ + + +# The Basics +At the heart of the ActiveStack API are [`SyncRequest`'s](src/main/java/com/percero/agents/sync/vo/SyncRequest.java) and [`SyncResponse`'s](src/main/java/com/percero/agents/sync/vo/SyncResponse.java). A specialized `SyncRequest` is sent to the ActiveStack Sync Engine and a `SyncResponse` is sent back the two being linked together by the `SyncResponse`.`correspondingMessageId`, which is the `ID` of the `SyncRequest`. + +## Login +Login is perhaps the most complicated of the API's in that it is meant to be generic and flexible enough to handle any type of authentication (OAuth, username/password, custom, etc). The main authentication engine is [`AuthService2`](src/main/java/com/percero/agents/auth/services/AuthService2.java). + +Login basically accepts some form of user credentials and returns a `UserID` and `ClientID` upon successful authentication. The `ClientID` is the main way that ActiveStack knows who the user is and also enables a single user to be simultaneously logged in on multipled devices. + +A successful login returns a [`UserToken`](src/main/java/com/percero/agents/auth/vo/UserToken.java) object that contains the [`User`](src/main/java/com/percero/agents/auth/vo/User.java), `clientId`, `deviceId`, and `token` (required for reauthentication). Typically, upon successful login, the app will issue a `findByExample` request for the class that represents the user in the application. For example, if `Person` is the class that represents the user, the app would issue a `findByExample` request with `theObject` payload: +``` +{ + "cn": "com.app.mo.Person", // Or whatever the actual class name of the `Person` object is + "userId": , // The `UserToken`.`User`.`ID` from the `AuthenticationResponse` +} +``` +This should result in the `Person` object identified by that User.ID to be returned by the ActiveStack SyncEngine. + +### [authenticate](src/main/java/com/percero/agents/auth/services/AuthService2.java#L47) +- Authenticates a user by their credentials. + - Request: [`AuthenticationRequest`](src/main/java/com/percero/agents/auth/vo/AuthenticationRequest.java) + - Response: [`AuthenticationResponse`](src/main/java/com/percero/agents/auth/vo/AuthenticationResponse.java) + - Parameters: + - `authProvider`: This is the name of the auth provider that will be used for authentication. The auth provider can either be built-in auth providers, or a custom defined auth provider. + - `credential`: This is a string that represents the user's credentials. Based on the authentication provider, this string is parsed accordingly to pull out the various parts of the credentials. + - Examples: + - [`BasicAuthCredential`](src/main/java/com/percero/agents/auth/vo/BasicAuthCredential.java): Handled by [`InMemoryAuthProvider`](src/main/java/com/percero/agents/auth/services/InMemoryAuthProvider.java) + - [`OAuthCredential`](src/main/java/com/percero/agents/auth/vo/OAuthCredential.java): Handled by [`GoogleAuthProvider`](src/main/java/com/percero/agents/auth/services/GoogleAuthProvider.java) + - AnonCredential: Handled by [`AnonAuthProvider`](src/main/java/com/percero/agents/auth/services/AnonAuthProvider.java) + +### [reauthenticate](src/main/java/com/percero/agents/auth/services/AuthService2.java#L83) +- Reauthenticates a user by a token (which is typically assigned upon successful authentication). + - Request: [`ReauthenticationRequest`](src/main/java/com/percero/agents/auth/vo/ReauthenticationRequest.java) + - Response: [`AuthenticationResponse`](src/main/java/com/percero/agents/auth/vo/AuthenticationResponse.java) + - Parameters: + - `authProvider`: This is the name of the auth provider that will be used for authentication. The auth provider can either be built-in auth providers, or a custom defined auth provider. + - `token`: This is the string token that was returned upon successful authentication. + +### [disconnect SyncEngine](src/main/java/com/percero/amqp/handlers/DisconnectHandler.java) +- Disconnects a client from the ActiveStack SyncEngine. This means that the client will no longer be pushed updates. Note that updates will be stored up for the client until they either reconnect or logout. + - Request: [`DisconnectRequest`](src/main/java/com/percero/agents/sync/vo/DisconnectRequest.java) + - Response: [`DisconnectResponse`](src/main/java/com/percero/agents/sync/vo/DisconnectResponse.java) + - Parameters: + - `userId` + - `clientId` + +### [disconnect Auth](https://github.com/ActiveStack/syncengine/blob/master/src/main/java/com/percero/agents/auth/services/AuthService.java#L706) +- Disconnects a client from ActiveStack Auth. + - Request: [`DisconnectRequest`](src/main/java/com/percero/agents/auth/vo/DisconnectRequest.java) + - Response: [`DisconnectResponse`](src/main/java/com/percero/agents/auth/vo/DisconnectResponse.java) + - Parameters: + - `userId` + - `clientId` + +### [logout](src/main/java/com/percero/amqp/handlers/LogoutHandler.java) +- Logs out a client from ActiveStack. This means that the client will no longer be notified of updates. Note that updates will NOT be stored up for the client. + - Request: [`LogoutRequest`](src/main/java/com/percero/agents/sync/vo/LogoutRequest.java) + - Response: null - Since the client has logged out, it is assumed they are not listening for any further messages, so no response is sent. + - Parameters: + - `userId` + - `clientId` + +## Core API + +- All `className` references assume that the corresponding class is part of the registered data model, meaning it is included in the `ActiveStack.Domain` module. + +### [connect](src/main/java/com/percero/amqp/handlers/ConnectHandler.java) +- Upon successful authentication, the ActiveStack Gateway will send a [`ConnectRequest`]() to the SyncEngine on behalf of the client. This is to let the SyncEngine know that this client has come online. +- NOTE: The client app itself is never aware of this `ConnectRequest`, it is handled automatically under the hood by the ActiveStack Gateway. However, the `ConnectResponse` IS sent to the client app so that it knows it is now connected to the SyncEngine and can start sending requests. + - Request: [`ConnectRequest`](src/main/java/com/percero/agents/sync/vo/ConnectRequest.java) + - Response: [`ConnectResponse`](src/main/java/com/percero/agents/sync/vo/ConnectResponse.java) + +### [reconnect](src/main/java/com/percero/amqp/handlers/ReconnectHandler.java) +- When a client loses connection to ActiveStack, it can send a [`ReconnectRequest`](src/main/java/com/percero/agents/sync/vo/ReconnectRequest.java) to the SyncEngine. This is to let the SyncEngine know that this client has come back online. + - Request: [`ReconnectRequest`](src/main/java/com/percero/agents/sync/vo/ReconnectRequest.java) + - Response: [`ReconnectResponse`](src/main/java/com/percero/agents/sync/vo/ReconnectResponse.java) + +### [findById](src/main/java/com/percero/amqp/handlers/FindByIdHandler.java) +- Retrieves the object identified by a `className` and an `ID`. The server will respond with a `findByIdResponse` containing either the result, or a NULL result indicating the specified object was not found, and registers the Client for any updates to that object. + - Request: [`FindByIdRequest`](https://github.com/ActiveStack/syncengine/blob/master/src/main/java/com/percero/agents/sync/vo/FindByIdRequest.java) + - Response: [`FindByIdResponse`](https://github.com/ActiveStack/syncengine/blob/master/src/main/java/com/percero/agents/sync/vo/FindByIdResponse.java) + - Parameters: + - `theClassName`: The name of the class + - `theClassId`: The ID of the object to find + - Note that the API should be able to handle inheritance. So "parentClass::ID" and "class::ID" should both return the same result (assuming that "class" inherits from "parentClass"). + +### [findByIds](src/main/java/com/percero/amqp/handlers/FindByIdsHandler.java) +- Retrieves a list of object identified by the `className` and a list of `ID`'s and registers the Client for any updates to those objects. + - Request: [`FindByIdsRequest`](https://github.com/ActiveStack/syncengine/blob/master/src/main/java/com/percero/agents/sync/vo/FindByIdsRequest.java) + - Response: [`FindByIdsResponse`](https://github.com/ActiveStack/syncengine/blob/master/src/main/java/com/percero/agents/sync/vo/FindByIdsResponse.java) + - Parameters: + - `theClassIdList`: [`ClassIDPairs`](src/main/java/com/percero/agents/sync/vo/ClassIDPairs.java) object which contains the `className` and a list of `ID`'s to retrieve + - Note that the API should be able to handle inheritance. So "parentClass::ID" and "class::ID" should both return the same result (assuming that "class" inherits from "parentClass"). + +### [getAllByName](src/main/java/com/percero/amqp/handlers/GetAllByNameHandler.java) +- Retrieves all objects of a particular class and registers the Client for any updates to those objects. + - Request: [`GetAllByNameRequest`](src/main/java/com/percero/agents/sync/vo/GetAllByNameRequest.java) + - Response: [`GetAllByNameResponse`](src/main/java/com/percero/agents/sync/vo/GetAllByNameResponse.java) + - Parameters: + - `theClassName`: The name of the class to get all objects. + - `pageSize` (optional): Number of items to return in result. + - `pageNumber` (optional): Desired page number + - `returnTotal` (optional): If set to `true`, returns the total number of objects to be returned. Typically used in the first call to determine exactly how many objects are expected. + +### [findByExample](src/main/java/com/percero/amqp/handlers/FindByExampleHandler.java) +- Retrieves all objects that match the supplied sample object and registers the Client for any updates to those objects. + - Request: [`FindByExampleRequest`](src/main/java/com/percero/agents/sync/vo/FindByExampleRequest.java) + - Response: [`FindByExampleResponse`](src/main/java/com/percero/agents/sync/vo/FindByExampleResponse.java) + - Parameters: + - `theObject`: A sample object of the domain model. Fields on the object that are set will be included as part of the filter criteria + +### [putObject](src/main/java/com/percero/amqp/handlers/PutObjectHandler.java) +- Updates an existing object + - Request: [`PutRequest`](src/main/java/com/percero/agents/sync/vo/PutRequest.java) + - Response: [`PutResponse`](src/main/java/com/percero/agents/sync/vo/PutResponse.java) + - Parameters: + - `theObject` + - `putTimestamp` (optional): The time this object was updated. This is used for conflict resolution + - `transId` (optional): A client defined transaction ID. Mostly used for tracking of updates, does NOT enforce a database transaction. + +### [createObject](src/main/java/com/percero/amqp/handlers/CreateObjectHandler.java) +- Creates a new object + - Request: [`CreateRequest`](src/main/java/com/percero/agents/sync/vo/CreateRequest.java) + - Response: [`CreateResponse`](src/main/java/com/percero/agents/sync/vo/CreateResponse.java) + - Parameters: + - `theObject`: The object to be created. If the object does NOT contain an ID, the ActiveStack Sync Engine will create one. + +### [removeObject](src/main/java/com/percero/amqp/handlers/RemoveObjectHandler.java) +- Removes an existing object + - Request: [`RemoveRequest`](src/main/java/com/percero/agents/sync/vo/RemoveRequest.java) + - Response: [`RemoveResponse`](src/main/java/com/percero/agents/sync/vo/RemoveResponse.java) + - Parameters: + - `removePair`: A [`ClassIDPair`](src/main/java/com/percero/agents/sync/vo/ClassIDPair.java) identifying the ID and class name of the object to be removed + +### [getChangeWatcher](src/main/java/com/percero/amqp/handlers/GetChangeWatcherHandler.java) +- Retrieves the value of a ChangeWatcher and registers the Client for any updates to that value. + - Request: [`PushCWUpdateRequest`](https://github.com/ActiveStack/syncengine/blob/master/src/main/java/com/percero/agents/sync/vo/PushCWUpdateRequest.java) + - Response: [`PushCWUpdateResponse`](https://github.com/ActiveStack/syncengine/blob/master/src/main/java/com/percero/agents/sync/vo/PushCWUpdateResponse.java) + - Parameters: + - `classIdPair`: A [`ClassIDPair`](src/main/java/com/percero/agents/sync/vo/ClassIDPair.java) identifying the ID and class name of the object that the ChangeWatcher hangs off of. + - `fieldName`: The name of the field that represents the ChangeWatcher. + - `params` (optional): An array of strings that represent the parameters that uniquely identify the ChangeWatcher. + +### [runServerProcess](src/main/java/com/percero/amqp/handlers/RunProcessHandler.java) +- Runs a custom server process. This process can be a custom piece of code, a defined HTTP process, a defined SQL stored procedure, or some other defined Connector. + - Request: [`RunServerProcessRequest`](https://github.com/ActiveStack/syncengine/blob/master/src/main/java/com/percero/agents/sync/vo/RunServerProcessRequest.java) + - Response: [`RunServerProcessResponse`](https://github.com/ActiveStack/syncengine/blob/master/src/main/java/com/percero/agents/sync/vo/RunServerProcessResponse.java) + - Parameters: + - `queryName`: The name of the process. To use a specific Connector (such as 'HTTP' or 'SQL_PROC' for database stored procedures), prefix the operation name of the Connector name and a ":". Example: "HTTP:fetchDataFromHttpEndpoint" + - `queryArguments` (optional): Any required parameters for the server process. Typically, this is passed as some sort of map (parameterName -> parameterValue) + + +## Push Notifications from SyncEngine +This is really where the real-time aspect of ActiveStack comes into play. The main point here is that clients are notified of updates to objects that they are currently interested in. It is up to the client SDK to respond appropriately to these update notifications. + +### `pushUpdate` +Sent whenever an object has been updated for which a client has registered to receive updates. +- [PutObject Pushes](src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java#L173) +- [Client Reconnect Push Updates](src/main/java/com/percero/agents/sync/services/SyncAgentService.java#L1357) +- [Change Watcher Pushes](src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java#L326) +- Response: [`PushUpdateResponse`](src/main/java/com/percero/agents/sync/vo/PushUpdateResponse.java) + +### `deleteUpdate` +Sent whenever an object has been deleted for which a client has registered to receive updates. +- [RemoveObject Pushes](src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java#L103) +- [Client Reconnect Push Deletes](src/main/java/com/percero/agents/sync/services/SyncAgentService.java#L1423) +- Response: [`PushDeleteResponse`](src/main/java/com/percero/agents/sync/vo/PushDeleteResponse.java) + + + diff --git a/pom.xml b/pom.xml index 8cb767e..8acb7d5 100644 --- a/pom.xml +++ b/pom.xml @@ -7,13 +7,14 @@ org.activestack syncengine - 1.1.59-SNAPSHOT + 1.1.70-SNAPSHOT - 3.2.4.RELEASE + + 4.2.5.RELEASE 1.6.11 - 1.19.0 - 1.19.0 + 1.21.0 + 1.21.0 1.9.5 @@ -28,72 +29,18 @@ aspectjweaver ${aspectj.version} - - junit - junit - 4.8.2 - test - + - org.mockito - mockito-core - ${mockito-core.version} - test + org.codehaus.jackson + jackson-mapper-asl + 1.9.13 - - org.codehaus.jackson - jackson-mapper-asl - 1.9.2 - - - org.hibernate - hibernate - 3.2.5.ga - - - asm - asm - - - asm-attrs - asm - - - cglib - cglib - - - - - javax.transaction - jta - 1.1 - - - - javax.persistence - com.springsource.javax.persistence - 1.0.0 - - - - org.hibernate - hibernate-annotations - 3.3.0.ga - - - - org.hibernate - hibernate-commons-annotations - 3.3.0.ga - - - - org.hibernate - ejb3-persistence - 1.0.2.GA - + + org.hibernate + hibernate-core + 5.1.0.Final + cglib @@ -126,23 +73,6 @@ boon 0.26 - - junit - junit - 4.8.2 - test - - - - org.springframework - spring-expression - ${spring.version} - - - org.springframework - spring-context - ${spring.version} - org.springframework @@ -157,53 +87,41 @@ org.springframework - spring-orm - ${spring.version} - - - org.springframework - spring-test - ${spring.version} - test - - - commons-logging - commons-logging - - - - - org.springframework - spring-tx + spring-context ${spring.version} org.springframework.amqp spring-rabbit - 1.3.6.RELEASE + 1.5.5.RELEASE org.springframework.data spring-data-redis - 1.4.0.RELEASE + 1.7.1.RELEASE + + + org.springframework + spring-orm + ${spring.version} redis.clients jedis 2.5.2 - - - - org.quartz-scheduler - quartz - 2.2.2 - - - org.quartz-scheduler - quartz-jobs - 2.2.2 - + + + + + org.quartz-scheduler + quartz + 2.2.2 + + + org.quartz-scheduler + quartz-jobs + 2.2.2 + cglib cglib-nodep @@ -229,11 +160,6 @@ log4j 1.2.16 - - - - - commons-dbcp commons-dbcp @@ -242,7 +168,7 @@ org.javassist javassist - 3.15.0-GA + 3.20.0-GA joda-time @@ -252,10 +178,7 @@ com.google.apis google-api-services-oauth2 - - v2-rev78-1.19.0 + v2-rev107-1.21.0 com.google.http-client @@ -270,7 +193,7 @@ com.google.apis google-api-services-admin-directory - directory_v1-rev42-1.19.0 + directory_v1-rev64-1.21.0 com.restfb @@ -344,6 +267,30 @@ + + junit + junit + 4.8.2 + test + + + org.mockito + mockito-core + ${mockito-core.version} + test + + + org.springframework + spring-test + ${spring.version} + test + + + commons-logging + commons-logging + + + com.h2database h2 diff --git a/src/main/java/com/percero/agents/auth/helpers/AccountHelper.java b/src/main/java/com/percero/agents/auth/helpers/AccountHelper.java index 7febf4d..1bcff8c 100644 --- a/src/main/java/com/percero/agents/auth/helpers/AccountHelper.java +++ b/src/main/java/com/percero/agents/auth/helpers/AccountHelper.java @@ -10,6 +10,7 @@ import com.percero.agents.sync.metadata.*; import com.percero.agents.sync.services.IDataProviderManager; import com.percero.agents.sync.services.ISyncAgentService; +import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.Client; import com.percero.framework.bl.IManifest; import com.percero.framework.bl.ManifestHelper; @@ -564,7 +565,7 @@ public void setupUserRoles(String userId, List serviceUserList) thr if (!isInaccurateList && !serviceUserRoleExists) { log.warn("Deleting role " + nextUserRole.getRoleName() + " for " + userId); - syncAgentService.systemDeleteObject(nextUserRole, null, true, new HashSet()); + syncAgentService.systemDeleteObject(BaseDataObject.toClassIdPair(nextUserRole), null, true); } else updatedUserRoles.add(nextUserRole); } diff --git a/src/main/java/com/percero/agents/auth/hibernate/AssociationExample.java b/src/main/java/com/percero/agents/auth/hibernate/AssociationExample.java deleted file mode 100644 index ece4d92..0000000 --- a/src/main/java/com/percero/agents/auth/hibernate/AssociationExample.java +++ /dev/null @@ -1,340 +0,0 @@ -package com.percero.agents.auth.hibernate; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.hibernate.Criteria; -import org.hibernate.EntityMode; -import org.hibernate.HibernateException; -import org.hibernate.criterion.CriteriaQuery; -import org.hibernate.criterion.Criterion; -import org.hibernate.criterion.Example.PropertySelector; -import org.hibernate.criterion.MatchMode; -import org.hibernate.criterion.Restrictions; -import org.hibernate.criterion.SimpleExpression; -import org.hibernate.engine.TypedValue; -import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.type.AbstractComponentType; -import org.hibernate.type.Type; -import org.hibernate.util.StringHelper; - -/** - * A copy of Hibernate's Example class, with modifications that allow you to - * include many-to-one and one-to-one associations in Query By Example (QBE) - * queries. - * - * @author original code by Gavin King, modified by jkelly - * @see Example and - * association class - */ -@SuppressWarnings("serial") -public class AssociationExample implements Criterion { - - private final Object entity; - @SuppressWarnings("rawtypes") - private final Set excludedProperties = new HashSet(); - private PropertySelector selector; - private boolean isLikeEnabled; - private boolean isIgnoreCaseEnabled; - private MatchMode matchMode; - private boolean includeAssociations = true; - - /** - * A strategy for choosing property values for inclusion in the query - * criteria - */ - -/** public static interface PropertySelector { - public boolean include(Object propertyValue, String propertyName, - Type type); - }**/ - - private static final PropertySelector NOT_NULL = new NotNullPropertySelector(); - private static final PropertySelector ALL = new AllPropertySelector(); - private static final PropertySelector NOT_NULL_OR_ZERO = new NotNullOrZeroPropertySelector(); - - static final class AllPropertySelector implements PropertySelector { - public boolean include(Object object, String propertyName, Type type) { - return true; - } - } - - static final class NotNullPropertySelector implements PropertySelector { - public boolean include(Object object, String propertyName, Type type) { - return object != null; - } - } - - static final class NotNullOrZeroPropertySelector implements - PropertySelector { - public boolean include(Object object, String propertyName, Type type) { - return object != null - && (!(object instanceof Number) || ((Number) object) - .longValue() != 0); - } - } - - /** - * Set the property selector - */ - public AssociationExample setPropertySelector(PropertySelector selector) { - this.selector = selector; - return this; - } - - /** - * Exclude zero-valued properties - */ - public AssociationExample excludeZeroes() { - setPropertySelector(NOT_NULL_OR_ZERO); - return this; - } - - /** - * Don't exclude null or zero-valued properties - */ - public AssociationExample excludeNone() { - setPropertySelector(ALL); - return this; - } - - /** - * Use the "like" operator for all string-valued properties - */ - public AssociationExample enableLike(MatchMode matchMode) { - isLikeEnabled = true; - this.matchMode = matchMode; - return this; - } - - /** - * Use the "like" operator for all string-valued properties - */ - public AssociationExample enableLike() { - return enableLike(MatchMode.EXACT); - } - - /** - * Ignore case for all string-valued properties - */ - public AssociationExample ignoreCase() { - isIgnoreCaseEnabled = true; - return this; - } - - /** - * Exclude a particular named property - */ - @SuppressWarnings("unchecked") - public AssociationExample excludeProperty(String name) { - excludedProperties.add(name); - return this; - } - - /** - * Create a new instance, which includes all non-null properties by default - * - * @param entity - * @return a new instance of Example - */ - public static AssociationExample create(Object entity) { - if (entity == null) - throw new NullPointerException("null AssociationExample"); - return new AssociationExample(entity, NOT_NULL); - } - - protected AssociationExample(Object entity, PropertySelector selector) { - this.entity = entity; - this.selector = selector; - } - - public String toString() { - return "example (" + entity + ')'; - } - - private boolean isPropertyIncluded(Object value, String name, Type type) { - return !excludedProperties.contains(name) - && selector.include(value, name, type) - && (!type.isAssociationType() || (type.isAssociationType() - && includeAssociations && !type.isCollectionType())); - } - - public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) - throws HibernateException { - - StringBuffer buf = new StringBuffer().append('('); - EntityPersister meta = criteriaQuery.getFactory().getEntityPersister( - criteriaQuery.getEntityName(criteria)); - String[] propertyNames = meta.getPropertyNames(); - Type[] propertyTypes = meta.getPropertyTypes(); - // TODO: get all properties, not just the fetched ones! - Object[] propertyValues = meta.getPropertyValues(entity, getEntityMode( - criteria, criteriaQuery)); - for (int i = 0; i < propertyNames.length; i++) { - Object propertyValue = propertyValues[i]; - String propertyName = propertyNames[i]; - - boolean isPropertyIncluded = i != meta.getVersionProperty() - && isPropertyIncluded(propertyValue, propertyName, - propertyTypes[i]); - if (isPropertyIncluded) { - if (propertyTypes[i].isComponentType()) { - appendComponentCondition(propertyName, propertyValue, - (AbstractComponentType) propertyTypes[i], criteria, - criteriaQuery, buf); - } else { - appendPropertyCondition(propertyName, propertyValue, - criteria, criteriaQuery, buf); - } - } - } - if (buf.length() == 1) - buf.append("1=1"); // yuck! - return buf.append(')').toString(); - } - - private static final Object[] TYPED_VALUES = new TypedValue[0]; - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public TypedValue[] getTypedValues(Criteria criteria, - CriteriaQuery criteriaQuery) throws HibernateException { - - EntityPersister meta = criteriaQuery.getFactory().getEntityPersister( - criteriaQuery.getEntityName(criteria)); - String[] propertyNames = meta.getPropertyNames(); - Type[] propertyTypes = meta.getPropertyTypes(); - // TODO: get all properties, not just the fetched ones! - Object[] values = meta.getPropertyValues(entity, getEntityMode( - criteria, criteriaQuery)); - List list = new ArrayList(); - for (int i = 0; i < propertyNames.length; i++) { - Object value = values[i]; - Type type = propertyTypes[i]; - String name = propertyNames[i]; - - boolean isPropertyIncluded = i != meta.getVersionProperty() - && isPropertyIncluded(value, name, type); - - if (isPropertyIncluded) { - if (propertyTypes[i].isComponentType()) { - addComponentTypedValues(name, value, - (AbstractComponentType) type, list, criteria, - criteriaQuery); - } else { - addPropertyTypedValue(value, type, list); - } - } - } - return (TypedValue[]) list.toArray(TYPED_VALUES); - } - - private EntityMode getEntityMode(Criteria criteria, - CriteriaQuery criteriaQuery) { - EntityPersister meta = criteriaQuery.getFactory().getEntityPersister( - criteriaQuery.getEntityName(criteria)); - EntityMode result = meta.guessEntityMode(entity); - if (result == null) { - throw new ClassCastException(entity.getClass().getName()); - } - return result; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - protected void addPropertyTypedValue(Object value, Type type, List list) { - if (value != null) { - if (value instanceof String) { - String string = (String) value; - if (isIgnoreCaseEnabled) - string = string.toLowerCase(); - if (isLikeEnabled) - string = matchMode.toMatchString(string); - value = string; - } - list.add(new TypedValue(type, value, null)); - } - } - - @SuppressWarnings("rawtypes") - protected void addComponentTypedValues(String path, Object component, - AbstractComponentType type, List list, Criteria criteria, - CriteriaQuery criteriaQuery) throws HibernateException { - - if (component != null) { - String[] propertyNames = type.getPropertyNames(); - Type[] subtypes = type.getSubtypes(); - Object[] values = type.getPropertyValues(component, getEntityMode( - criteria, criteriaQuery)); - for (int i = 0; i < propertyNames.length; i++) { - Object value = values[i]; - Type subtype = subtypes[i]; - String subpath = StringHelper.qualify(path, propertyNames[i]); - if (isPropertyIncluded(value, subpath, subtype)) { - if (subtype.isComponentType()) { - addComponentTypedValues(subpath, value, - (AbstractComponentType) subtype, list, - criteria, criteriaQuery); - } else { - addPropertyTypedValue(value, subtype, list); - } - } - } - } - } - - protected void appendPropertyCondition(String propertyName, - Object propertyValue, Criteria criteria, CriteriaQuery cq, - StringBuffer buf) throws HibernateException { - Criterion crit; - if (propertyValue != null) { - boolean isString = propertyValue instanceof String; - SimpleExpression se = (isLikeEnabled && isString) ? Restrictions - .like(propertyName, propertyValue) : Restrictions.eq( - propertyName, propertyValue); - crit = (isIgnoreCaseEnabled && isString) ? se.ignoreCase() : se; - } else { - crit = Restrictions.isNull(propertyName); - } - String critCondition = crit.toSqlString(criteria, cq); - if (buf.length() > 1 && critCondition.trim().length() > 0) - buf.append(" and "); - buf.append(critCondition); - } - - protected void appendComponentCondition(String path, Object component, - AbstractComponentType type, Criteria criteria, - CriteriaQuery criteriaQuery, StringBuffer buf) - throws HibernateException { - - if (component != null) { - String[] propertyNames = type.getPropertyNames(); - Object[] values = type.getPropertyValues(component, getEntityMode( - criteria, criteriaQuery)); - Type[] subtypes = type.getSubtypes(); - for (int i = 0; i < propertyNames.length; i++) { - String subpath = StringHelper.qualify(path, propertyNames[i]); - Object value = values[i]; - if (isPropertyIncluded(value, subpath, subtypes[i])) { - Type subtype = subtypes[i]; - if (subtype.isComponentType()) { - appendComponentCondition(subpath, value, - (AbstractComponentType) subtype, criteria, - criteriaQuery, buf); - } else { - appendPropertyCondition(subpath, value, criteria, - criteriaQuery, buf); - } - } - } - } - } - - public boolean isIncludeAssociations() { - return includeAssociations; - } - - public void setIncludeAssociations(boolean includeAssociations) { - this.includeAssociations = includeAssociations; - } -} diff --git a/src/main/java/com/percero/agents/auth/hibernate/AuthHibernateUtils.java b/src/main/java/com/percero/agents/auth/hibernate/AuthHibernateUtils.java index dbd7478..cc2c9e0 100644 --- a/src/main/java/com/percero/agents/auth/hibernate/AuthHibernateUtils.java +++ b/src/main/java/com/percero/agents/auth/hibernate/AuthHibernateUtils.java @@ -16,12 +16,11 @@ import javax.persistence.Entity; import org.apache.log4j.Logger; -import org.hibernate.collection.PersistentBag; -import org.hibernate.collection.PersistentList; -import org.hibernate.collection.PersistentMap; -import org.hibernate.collection.PersistentSet; -import org.hibernate.collection.PersistentSortedSet; -import org.hibernate.engine.SessionImplementor; +import org.hibernate.collection.internal.PersistentBag; +import org.hibernate.collection.internal.PersistentList; +import org.hibernate.collection.internal.PersistentMap; +import org.hibernate.collection.internal.PersistentSet; +import org.hibernate.collection.internal.PersistentSortedSet; import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxyHelper; @@ -93,8 +92,8 @@ else if (object instanceof HibernateProxy) } else if (fieldObject instanceof PersistentList) { try { - PersistentList pList = (PersistentList) fieldObject; - SessionImplementor session = pList.getSession(); + org.hibernate.collection.internal.PersistentList pList = (org.hibernate.collection.internal.PersistentList) fieldObject; + org.hibernate.engine.spi.SessionImplementor session = pList.getSession(); if (session != null && session.isOpen()) { List ar = new ArrayList(); for (Object ob : pList) { @@ -109,8 +108,8 @@ else if (fieldObject instanceof PersistentList) { } } else if (fieldObject instanceof PersistentBag) { try { - PersistentBag pBag = (PersistentBag) fieldObject; - SessionImplementor session = pBag.getSession(); + org.hibernate.collection.internal.PersistentBag pBag = (org.hibernate.collection.internal.PersistentBag) fieldObject; + org.hibernate.engine.spi.SessionImplementor session = pBag.getSession(); if (session != null && session.isOpen()) { List ar = new ArrayList(); for (Object ob : pBag) { @@ -125,8 +124,8 @@ else if (fieldObject instanceof PersistentList) { } } else if (fieldObject instanceof PersistentSortedSet) { try { - PersistentSortedSet pSortedSet = (PersistentSortedSet) fieldObject; - SessionImplementor session = pSortedSet.getSession(); + org.hibernate.collection.internal.PersistentSortedSet pSortedSet = (org.hibernate.collection.internal.PersistentSortedSet) fieldObject; + org.hibernate.engine.spi.SessionImplementor session = pSortedSet.getSession(); if (session != null && session.isOpen()) { SortedSet ar = new TreeSet(); for (Object ob : pSortedSet) { @@ -141,8 +140,8 @@ else if (fieldObject instanceof PersistentList) { } } else if (fieldObject instanceof PersistentSet) { try { - PersistentSet pSet = (PersistentSet) fieldObject; - SessionImplementor session = pSet.getSession(); + org.hibernate.collection.internal.PersistentSet pSet = (org.hibernate.collection.internal.PersistentSet) fieldObject; + org.hibernate.engine.spi.SessionImplementor session = pSet.getSession(); if (session != null && session.isOpen()) { Set ar = new HashSet(); for (Object ob : pSet) { @@ -157,8 +156,8 @@ else if (fieldObject instanceof PersistentList) { } } else if (fieldObject instanceof PersistentMap) { try { - PersistentMap pMap = (PersistentMap) fieldObject; - SessionImplementor session = pMap.getSession(); + org.hibernate.collection.internal.PersistentMap pMap = (org.hibernate.collection.internal.PersistentMap) fieldObject; + org.hibernate.engine.spi.SessionImplementor session = pMap.getSession(); if (session != null && session.isOpen()) { Map hm = new HashMap(); for (Object nextKey : pMap.keySet()) { diff --git a/src/main/java/com/percero/agents/auth/hibernate/AuthSessionManager.java b/src/main/java/com/percero/agents/auth/hibernate/AuthSessionManager.java deleted file mode 100644 index b71643a..0000000 --- a/src/main/java/com/percero/agents/auth/hibernate/AuthSessionManager.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.percero.agents.auth.hibernate; - -import org.apache.log4j.Logger; -import org.hibernate.HibernateException; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class AuthSessionManager implements ISessionManager { - - private static Logger log = Logger.getLogger(AuthSessionManager.class); - - @Autowired - SessionFactory sessionFactoryAuth; - public void setSessionFactoryAuth(SessionFactory value) { - if (value != null) - log.debug("Setting sessionFactoryAuth to " + value.toString()); - else - log.debug("Setting sessionFactoryAuth to NULL"); - sessionFactoryAuth = value; - } - public SessionFactory getSessionFactoryAuth() { - return sessionFactoryAuth; - } - - public Session getSession() throws HibernateException { - return sessionFactoryAuth.openSession(); - } - - public Session getCurrentSession() { - return sessionFactoryAuth.getCurrentSession(); - } - -} \ No newline at end of file diff --git a/src/main/java/com/percero/agents/auth/hibernate/BaseDataObjectPropertySelector.java b/src/main/java/com/percero/agents/auth/hibernate/BaseDataObjectPropertySelector.java deleted file mode 100644 index d3c0c51..0000000 --- a/src/main/java/com/percero/agents/auth/hibernate/BaseDataObjectPropertySelector.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.percero.agents.auth.hibernate; - -import java.util.Date; -import java.util.List; - -import org.hibernate.criterion.Example.PropertySelector; -import org.hibernate.type.IntegerType; -import org.hibernate.type.StringType; -import org.hibernate.type.TimestampType; -import org.hibernate.type.Type; - -import com.percero.agents.auth.vo.IAuthCachedObject; - -@SuppressWarnings("serial") -public class BaseDataObjectPropertySelector implements PropertySelector { - - public BaseDataObjectPropertySelector(List excludeProps) { - excludeProperties = excludeProps; - } - - public List excludeProperties = null; - - public boolean include(Object propertyValue, String propertyName, Type type) { - if (propertyValue == null) { - return false; - } else if (excludeProperties != null && excludeProperties.contains(propertyName)) { - return false; - } - - if (type instanceof StringType) { - if (((String)propertyValue).length() == 0) { - return false; - } else { - return true; - } - } else if (type.isEntityType()) { - if (propertyValue instanceof IAuthCachedObject) { - if (((IAuthCachedObject)propertyValue).getID() != null && !((IAuthCachedObject)propertyValue).getID().equals("0")) { - return true; - } else { - return false; - } - } else { - return false; - } - } else if (type instanceof IntegerType) { - if (((Integer)propertyValue) != 0) { - return true; - } else { - return false; - } - } else if (type instanceof TimestampType) { - if (((Date)propertyValue).getTime() != 0) { - return true; - } else { - return false; - } - } - return true; - } - -} diff --git a/src/main/java/com/percero/agents/auth/hibernate/ISessionManager.java b/src/main/java/com/percero/agents/auth/hibernate/ISessionManager.java deleted file mode 100644 index 01a6ec1..0000000 --- a/src/main/java/com/percero/agents/auth/hibernate/ISessionManager.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.percero.agents.auth.hibernate; - -import org.hibernate.Session; - -public interface ISessionManager { - - public Session getSession() throws Exception; - public Session getCurrentSession() throws Exception; - -} \ No newline at end of file diff --git a/src/main/java/com/percero/agents/auth/services/AuthService.java b/src/main/java/com/percero/agents/auth/services/AuthService.java index 71b09bf..3f96fd3 100644 --- a/src/main/java/com/percero/agents/auth/services/AuthService.java +++ b/src/main/java/com/percero/agents/auth/services/AuthService.java @@ -1,13 +1,24 @@ package com.percero.agents.auth.services; -import com.percero.agents.auth.helpers.IAccountHelper; -import com.percero.agents.auth.hibernate.AssociationExample; -import com.percero.agents.auth.hibernate.AuthHibernateUtils; -import com.percero.agents.auth.hibernate.BaseDataObjectPropertySelector; -import com.percero.agents.auth.vo.*; -import com.percero.agents.sync.access.IAccessManager; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + import org.apache.log4j.Logger; -import org.hibernate.*; +import org.hibernate.Criteria; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.StaleStateException; +import org.hibernate.Transaction; +import org.hibernate.criterion.Restrictions; import org.hibernate.exception.LockAcquisitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -15,7 +26,19 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; -import java.util.*; +import com.percero.agents.auth.helpers.IAccountHelper; +import com.percero.agents.auth.hibernate.AuthHibernateUtils; +import com.percero.agents.auth.vo.AuthProvider; +import com.percero.agents.auth.vo.OAuthResponse; +import com.percero.agents.auth.vo.OAuthToken; +import com.percero.agents.auth.vo.ServiceIdentifier; +import com.percero.agents.auth.vo.ServiceUser; +import com.percero.agents.auth.vo.SvcAppRole; +import com.percero.agents.auth.vo.User; +import com.percero.agents.auth.vo.UserAccount; +import com.percero.agents.auth.vo.UserIdentifier; +import com.percero.agents.auth.vo.UserToken; +import com.percero.agents.sync.access.IAccessManager; /** * The AuthService is responsible for managing authentication of users within the Percero framework. The AuthService @@ -75,31 +98,6 @@ public AuthService() { } - @SuppressWarnings("rawtypes") - protected List findByExample(Object theQueryObject, - List excludeProperties) { - Session s = null; - try { - s = sessionFactoryAuth.openSession(); - 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(); - return (List) AuthHibernateUtils.cleanObject(result); - } catch (Exception e) { - log.error("Unable to findByExample", e); - } finally { - if (s != null) - s.close(); - } - return null; - } - /* (non-Javadoc) * @see com.com.percero.agents.auth.services.IAuthService#authenticateOAuthCode(com.com.percero.agents.auth.vo.AuthProvider, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.com.percero.agents.auth.vo.OAuthToken) */ @@ -427,20 +425,18 @@ private UserAccount updateUserAccountToken(UserAccount theQueryObject, Boolean c UserAccount theFoundUserAccount = null; Session s = null; try { - List excludeProperties = new ArrayList(); - excludeProperties.add("accessToken"); - excludeProperties.add("refreshToken"); - excludeProperties.add("isAdmin"); - excludeProperties.add("isSuspended"); - List userAccounts = findByExample(theQueryObject, - excludeProperties); + s = sessionFactoryAuth.openSession(); + Criteria criteria = s.createCriteria(UserAccount.class) + .add(Restrictions.eq("accountId", theQueryObject.getAccountId())) + .add(Restrictions.eq("authProviderID", theQueryObject.getAuthProviderID())); + List result = criteria.list(); + List userAccounts = (List) AuthHibernateUtils.cleanObject(result); // It is possible that this Service Provider (or this use case) does not have an AccessToken, so set one here. if (theQueryObject.getAccessToken() == null || theQueryObject.getAccessToken().length() == 0) theQueryObject.setAccessToken(getRandomId()); - if ((userAccounts instanceof List) - && ((List) userAccounts).size() > 0) { + if (userAccounts != null && !userAccounts.isEmpty()) { // Found a valid UserAccount. List userAccountList = (List) userAccounts; theFoundUserAccount = (UserAccount) userAccountList.get(0); @@ -449,7 +445,6 @@ private UserAccount updateUserAccountToken(UserAccount theQueryObject, Boolean c theFoundUserAccount.setAccessToken(theQueryObject.getAccessToken()); if(theQueryObject.getRefreshToken() != null && !theQueryObject.getRefreshToken().isEmpty()) theFoundUserAccount.setRefreshToken(theQueryObject.getRefreshToken()); - s = sessionFactoryAuth.openSession(); Transaction tx = s.beginTransaction(); tx.begin(); theFoundUserAccount = (UserAccount) s @@ -457,8 +452,6 @@ private UserAccount updateUserAccountToken(UserAccount theQueryObject, Boolean c tx.commit(); } } else if (createIfNotExist) { - s = sessionFactoryAuth.openSession(); - User theUser = null; // Attempt to find this user by finding a matching UserIdentifier. @@ -520,8 +513,6 @@ private UserAccount updateUserAccountToken(UserAccount theQueryObject, Boolean c // Now enter in the UserIdentifiers for this User. if (serviceUser.getIdentifiers() != null && serviceUser.getIdentifiers().size() > 0) { - if (s == null) - s = sessionFactoryAuth.openSession(); Transaction tx = s.beginTransaction(); Query q = null; for(ServiceIdentifier nextServiceIdentifier : serviceUser.getIdentifiers()) { @@ -563,17 +554,16 @@ private UserToken loginUserAccount(UserAccount theUserAccount, String clientId, UserToken theUserToken = null; if (theUserAccount != null) { Date currentDate = new Date(); - UserToken queryUserToken = new UserToken(); - queryUserToken.setUser(theUserAccount.getUser()); - queryUserToken.setClientId(clientId); - List userTokenResult = findByExample(queryUserToken, null); + s = sessionFactoryAuth.openSession(); + Criteria criteria = s.createCriteria(UserToken.class).add(Restrictions.eq("clientId", clientId)) + .add(Restrictions.eq("user.ID", theUserAccount.getUser().getID())); + List result = criteria.list(); + List userTokenResult = (List) AuthHibernateUtils.cleanObject(result); if ( !userTokenResult.isEmpty() ) { theUserToken = (UserToken) userTokenResult.get(0); } - if (s == null) - s = sessionFactoryAuth.openSession(); Transaction tx = s.beginTransaction(); tx.begin(); @@ -646,9 +636,15 @@ private UserToken loginUserAccount(UserAccount theUserAccount, String clientId, * @see com.com.percero.agents.auth.services.IAuthService#logoutUser(java.lang.String, java.lang.String, java.lang.String) */ public Boolean logoutUser(String aUserId, String aToken, String aClientId) { + Set clientIds = new HashSet(1); + clientIds.add(aClientId); + return logoutUser(aUserId, aToken, clientIds); + } + + public Boolean logoutUser(String aUserId, String aToken, Set clientIds) { Boolean result = false; boolean validUser = StringUtils.hasText(aUserId); - boolean validClient = StringUtils.hasText(aClientId); + boolean validClient = clientIds != null && !clientIds.isEmpty(); boolean validToken = StringUtils.hasText(aToken); // If neither a valid user or a valid client, then no one to logout. @@ -661,17 +657,16 @@ public Boolean logoutUser(String aUserId, String aToken, String aClientId) { // Match EITHER the ClientID OR the Token if (validClient && validToken) { - log.debug("Logging out Client: " + aClientId + ", Token: " + aToken); - deleteUserTokenSql += " (clientId=:clientId OR token=:token) "; + log.debug("Logging out Client(s): " + StringUtils.collectionToCommaDelimitedString(clientIds) + " / Token: " + aToken); + deleteUserTokenSql += " (clientId IN (" + StringUtils.collectionToDelimitedString(clientIds, ",", "\"", "\"") + ") OR token=:token) "; } else if (validToken) { - log.debug("Logging out Token: " + aToken); log.debug("Logging out Token: " + aToken); deleteUserTokenSql += " token=:token "; } else if (validClient) { - log.debug("Logging out Client: " + aClientId); - deleteUserTokenSql += " clientId=:clientId "; + log.debug("Logging out Client(s): " + StringUtils.collectionToCommaDelimitedString(clientIds)); + deleteUserTokenSql += " clientId IN (" + StringUtils.collectionToDelimitedString(clientIds, ",", "\"", "\"") + ") "; } else if (validUser) { // This will log out ALL of the User's devices, logging them out completely. @@ -687,13 +682,12 @@ else if (validUser) { if (validClient && validToken) { deleteQuery.setString("token", aToken); - deleteQuery.setString("clientId", aClientId); } else if (validToken) { deleteQuery.setString("token", aToken); } else if (validClient) { - deleteQuery.setString("clientId", aClientId); + // Do nothing. } else if (validUser) { deleteQuery.setString("user_ID", aUserId); @@ -904,75 +898,60 @@ public ServiceUser getServiceProviderServiceUser(String accessToken, String refr ServiceUser serviceUser = null; try { - - if (anonAuthEnabled && StringUtils.hasText(anonAuthCode)) { - if (refreshToken != null && refreshToken.equals(anonAuthCode)) { - serviceUser = new ServiceUser(); - serviceUser.setFirstName("ANON"); - serviceUser.setLastName("ANON"); - serviceUser.setId("ANON"); - serviceUser.setAuthProviderID(AuthProvider.ANON.toString()); - serviceUser.setRefreshToken(anonAuthCode); - - List roles = new ArrayList(); - String[] roleNames = anonAuthRoleNames.split(","); - for(int i = 0; i < roleNames.length; i++) { - if (roleNames[i] != null && !roleNames[i].isEmpty()) - roles.add(roleNames[i]); - } - serviceUser.setRoleNames(roles); - serviceUser.setAreRoleNamesAccurate(true); - return serviceUser; - } - } - - /**if (AuthProvider.LINKEDIN.equals(authProviderID)) { - // LinkedInHelper linkedInHelper = new LinkedInHelper(); - // ServiceUser liServiceUser = linkedInHelper.getServiceUser( - // svcOauth.getAppKey(), svcOauthSecret.getAppToken(), - // accessToken, - // refreshToken, - // svcOauth.getServiceApplication().getAppDomain()); - // serviceUser = liServiceUser; - } - else */if (AuthProvider.FACEBOOK.equals(authProviderID)) { + if (AuthProvider.FACEBOOK.name().equalsIgnoreCase(authProviderID)) { ServiceUser fbServiceUser = facebookHelper.getServiceUser( accessToken, accountId); serviceUser = fbServiceUser; } - else if (AuthProvider.GOOGLE.equals(authProviderID)) { + else if (AuthProvider.GOOGLE.name().equalsIgnoreCase(authProviderID)) { ServiceUser glServiceUser = googleHelper.authenticateAccessToken(accessToken, refreshToken, accountId); //ServiceUser glServiceUser = googleHelper.retrieveServiceUser(accountId); serviceUser = glServiceUser; } - else if (AuthProvider.GITHUB.equals(authProviderID)) { + else if (AuthProvider.GITHUB.name().equalsIgnoreCase(authProviderID)) { ServiceUser glServiceUser = githubHelper.getServiceUser(accessToken, refreshToken); serviceUser = glServiceUser; } - else if (AuthProvider.LINKEDIN.equals(authProviderID)) { + else if (AuthProvider.LINKEDIN.name().equalsIgnoreCase(authProviderID)) { ServiceUser liServiceUser = linkedInHelper.getServiceUser(accessToken, refreshToken); serviceUser = liServiceUser; } - else if(AuthProvider.ANON.equals(authProviderID)){ - serviceUser = new ServiceUser(); - serviceUser.setEmails(new ArrayList()); - serviceUser.getEmails().add("blargblarg@com.percero.com"); - serviceUser.setAccessToken("blargblarg"); - serviceUser.setFirstName("ANONYMOUS"); - serviceUser.setId("ANONYMOUS"); - serviceUser.setAuthProviderID(AuthProvider.ANON.toString()); + else if(AuthProvider.ANON.name().equalsIgnoreCase(authProviderID)){ + // We only allow anonymous if anonAuthEnabled is TRUE AND the anonAuthCode matches the refresh token. + if (anonAuthEnabled && StringUtils.hasText(anonAuthCode)) { + if (refreshToken != null && refreshToken.equals(anonAuthCode)) { + serviceUser = new ServiceUser(); + serviceUser.setFirstName("ANON"); + serviceUser.setLastName("ANON"); + serviceUser.setId("ANON"); + serviceUser.setAuthProviderID(AuthProvider.ANON.toString()); + serviceUser.setRefreshToken(anonAuthCode); + + List roles = new ArrayList(); + String[] roleNames = anonAuthRoleNames != null ? anonAuthRoleNames.split(",") : new String[0]; + for(int i = 0; i < roleNames.length; i++) { + if (roleNames[i] != null && !roleNames[i].isEmpty()) + roles.add(roleNames[i]); + } + serviceUser.setRoleNames(roles); + serviceUser.setAreRoleNamesAccurate(true); + } + } } - else - { + else { log.warn("ServiceProvider not yet supported: " + authProviderID); } } catch (Exception e) { - e.printStackTrace(); + log.error("Error getting Service User from Auth Provider", e); } - if (serviceUser != null) + if (serviceUser != null) { + // In case the client has used a different casing of the Auth + // Provider ID, we want to return the exact same casing. + // Ex: LinkedIn vs. linkedIn serviceUser.setAuthProviderID(authProviderID); + } return serviceUser; } diff --git a/src/main/java/com/percero/agents/auth/services/AuthService2.java b/src/main/java/com/percero/agents/auth/services/AuthService2.java index 298648f..a3d7a5d 100644 --- a/src/main/java/com/percero/agents/auth/services/AuthService2.java +++ b/src/main/java/com/percero/agents/auth/services/AuthService2.java @@ -1,28 +1,56 @@ package com.percero.agents.auth.services; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.ServiceConfigurationError; +import java.util.UUID; + +import org.apache.log4j.Logger; +import org.hibernate.Criteria; +import org.hibernate.NonUniqueResultException; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.criterion.Restrictions; +import org.hibernate.exception.LockAcquisitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + import com.percero.agents.auth.helpers.RoleHelper; import com.percero.agents.auth.helpers.UserAnchorHelper; import com.percero.agents.auth.helpers.UserIdentifierHelper; -import com.percero.agents.auth.hibernate.AssociationExample; import com.percero.agents.auth.hibernate.AuthHibernateUtils; -import com.percero.agents.auth.hibernate.BaseDataObjectPropertySelector; -import com.percero.agents.auth.vo.*; +import com.percero.agents.auth.vo.AuthProviderResponse; +import com.percero.agents.auth.vo.AuthenticationRequest; +import com.percero.agents.auth.vo.AuthenticationResponse; +import com.percero.agents.auth.vo.IUserAnchor; +import com.percero.agents.auth.vo.IUserIdentifier; +import com.percero.agents.auth.vo.IUserRole; +import com.percero.agents.auth.vo.ReauthenticationRequest; +import com.percero.agents.auth.vo.ServiceIdentifier; +import com.percero.agents.auth.vo.ServiceUser; +import com.percero.agents.auth.vo.User; +import com.percero.agents.auth.vo.UserAccount; +import com.percero.agents.auth.vo.UserIdentifier; +import com.percero.agents.auth.vo.UserToken; import com.percero.agents.sync.exceptions.SyncDataException; -import com.percero.agents.sync.metadata.*; +import com.percero.agents.sync.metadata.EntityImplementation; +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.PropertyImplementation; +import com.percero.agents.sync.metadata.PropertyImplementationParam; +import com.percero.agents.sync.metadata.RelationshipImplementation; import com.percero.agents.sync.services.ISyncAgentService; +import com.percero.agents.sync.vo.BaseDataObject; import com.percero.framework.bl.IManifest; import com.percero.framework.bl.ManifestHelper; import com.percero.framework.vo.IPerceroObject; -import org.apache.log4j.Logger; -import org.hibernate.*; -import org.hibernate.criterion.Restrictions; -import org.hibernate.exception.LockAcquisitionException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -import java.lang.reflect.InvocationTargetException; -import java.util.*; /** * This class handles AuthenticationRequest type authentication @@ -105,28 +133,30 @@ public AuthenticationResponse reauthenticate(ReauthenticationRequest request){ * @param serviceUser * @return */ - private UserAccount findUserAccount(ServiceUser serviceUser) throws SyncDataException { + @SuppressWarnings("rawtypes") + private UserAccount findUserAccount(ServiceUser serviceUser) throws SyncDataException { UserAccount theFoundUserAccount = null; - UserAccount theQueryObject = new UserAccount(); - theQueryObject.setAccountId(serviceUser.getId()); - theQueryObject.setAuthProviderID(serviceUser.getAuthProviderID()); - - List excludeProperties = new ArrayList(); - excludeProperties.add("accessToken"); - excludeProperties.add("refreshToken"); - excludeProperties.add("isAdmin"); - excludeProperties.add("isSuspended"); - List userAccounts = findByExample(theQueryObject, - excludeProperties); - - if ((userAccounts instanceof List)) { - List listUserAccounts = (List) userAccounts; - if (listUserAccounts.size() == 1) { + List userAccounts = null; + Session s = null; + try { + s = sessionFactoryAuth.openSession(); + Criteria criteria = s.createCriteria(UserAccount.class) + .add(Restrictions.eq("accountId", serviceUser.getId())) + .add(Restrictions.eq("authProviderID", serviceUser.getAuthProviderID())); + List result = criteria.list(); + userAccounts = (List) AuthHibernateUtils.cleanObject(result); + } finally { + if (s != null) + s.close(); + } + + if (userAccounts != null && !userAccounts.isEmpty()) { + if (userAccounts.size() == 1) { // Found a valid UserAccount. - theFoundUserAccount = (UserAccount) listUserAccounts.get(0); + theFoundUserAccount = (UserAccount) userAccounts.get(0); } - else if (listUserAccounts.size() > 1) { - throw new SyncDataException(listUserAccounts.size() + " UserAccounts found for serviceUser " + serviceUser.getId(), 1001); + else if (userAccounts.size() > 1) { + throw new SyncDataException(userAccounts.size() + " UserAccounts found for serviceUser " + serviceUser.getId(), 1001); } } @@ -262,17 +292,16 @@ private UserToken loginUserAccount(UserAccount theUserAccount, String clientId, UserToken theUserToken = null; try { Date currentDate = new Date(); - UserToken queryUserToken = new UserToken(); - queryUserToken.setUser(theUserAccount.getUser()); - queryUserToken.setClientId(clientId); - List userTokenResult = findByExample(queryUserToken, null); + s = sessionFactoryAuth.openSession(); + Criteria criteria = s.createCriteria(UserToken.class).add(Restrictions.eq("clientId", clientId)) + .add(Restrictions.eq("user.ID", theUserAccount.getUser().getID())); + List result = criteria.list(); + List userTokenResult = (List) AuthHibernateUtils.cleanObject(result); if ( !userTokenResult.isEmpty() ) { theUserToken = (UserToken) userTokenResult.get(0); } - if (s == null) - s = sessionFactoryAuth.openSession(); Transaction tx = s.beginTransaction(); tx.begin(); @@ -318,31 +347,6 @@ private UserToken loginUserAccount(UserAccount theUserAccount, String clientId, return theUserToken; } - @SuppressWarnings("rawtypes") - protected List findByExample(Object theQueryObject, - List excludeProperties) { - Session s = null; - try { - s = sessionFactoryAuth.openSession(); - 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(); - return (List) AuthHibernateUtils.cleanObject(result); - } catch (Exception e) { - logger.error("Unable to findByExample", e); - } finally { - if (s != null) - s.close(); - } - return null; - } - private static String getRandomId() { UUID randomId = UUID.randomUUID(); return randomId.toString(); @@ -570,7 +574,6 @@ else if (result.getUserId() == null || result.getUserId().isEmpty()) { return null; } - @SuppressWarnings({ "unchecked" }) public void setupUserRoles(User user, ServiceUser serviceUser) throws Exception { // Session s = appSessionFactory.openSession(); @@ -599,7 +602,7 @@ else if (serviceUser.getRoleNames().contains(nextUserRole.getRoleName())) { if (!isInaccurateList && !serviceUserRoleExists) { logger.warn("Deleting role " + nextUserRole.getRoleName() + " for " + user.getID()); - syncAgentService.systemDeleteObject(nextUserRole, null, true, new HashSet()); + syncAgentService.systemDeleteObject(BaseDataObject.toClassIdPair(nextUserRole), null, true); } else updatedUserRoles.add(nextUserRole); } diff --git a/src/main/java/com/percero/agents/auth/services/GoogleHelper.java b/src/main/java/com/percero/agents/auth/services/GoogleHelper.java index 7262383..dd21f6c 100644 --- a/src/main/java/com/percero/agents/auth/services/GoogleHelper.java +++ b/src/main/java/com/percero/agents/auth/services/GoogleHelper.java @@ -90,7 +90,7 @@ public class GoogleHelper implements IAuthHelper { @Autowired @Value("$pf{oauth.google.webCallbackUrl}") private String webRedirectUrl; - @Autowired @Value("$pf{oauth.google.domain}") + @Autowired @Value("$pf{oauth.google.domain:}") private String domain; @Autowired @Value("$pf{oauth.google.admin}") @@ -251,7 +251,7 @@ public ServiceUser authenticateOAuthCode(String code, String redirectUri) throws return serviceUser; } } catch(Exception e) { - log.error("Unable to get authenticate oauth code", e); + log.error("Unable to get authenticate oauth code: " + e.getMessage()); return null; } } @@ -660,6 +660,9 @@ private Userinfoplus getUserInfo(Oauth2 oauth2) throws IOException { } catch(GoogleJsonResponseException gjre) { log.info("Error getting Google Profile Information: " + gjre.getMessage()); return null; + } catch(Exception e) { + log.info("Error getting Google Profile Information: " + e.getMessage()); + return null; } } diff --git a/src/main/java/com/percero/agents/auth/services/IAuthService.java b/src/main/java/com/percero/agents/auth/services/IAuthService.java index 00e3bc0..1bc4132 100644 --- a/src/main/java/com/percero/agents/auth/services/IAuthService.java +++ b/src/main/java/com/percero/agents/auth/services/IAuthService.java @@ -3,7 +3,6 @@ import java.util.List; import java.util.Set; -import com.percero.agents.auth.vo.AuthProvider; import com.percero.agents.auth.vo.OAuthResponse; import com.percero.agents.auth.vo.OAuthToken; import com.percero.agents.auth.vo.ServiceUser; @@ -109,8 +108,9 @@ public interface IAuthService { * * @param aUserId * @param aToken - * @param aClientId + * @param clientIds * @return TRUE if user/client successfully logged out, FALSE if user/client unable to be logged out */ - public Boolean logoutUser(String aUserId, String aToken, String aClientId); + public Boolean logoutUser(String aUserId, String aToken, Set clientIds); + public Boolean logoutUser(String aUserId, String aToken, String clientId); } diff --git a/src/main/java/com/percero/agents/auth/vo/DisconnectRequest.java b/src/main/java/com/percero/agents/auth/vo/DisconnectRequest.java index c52f021..c8abf03 100644 --- a/src/main/java/com/percero/agents/auth/vo/DisconnectRequest.java +++ b/src/main/java/com/percero/agents/auth/vo/DisconnectRequest.java @@ -1,5 +1,22 @@ package com.percero.agents.auth.vo; +import java.util.Set; + public class DisconnectRequest extends AuthRequest { + private String existingClientId; + public String getExistingClientId() { + return existingClientId; + } + public void setExistingClientId(String existingClientId) { + this.existingClientId = existingClientId; + } + + private Set existingClientIds; + public Set getExistingClientIds() { + return existingClientIds; + } + public void setExistingClientIds(Set existingClientIds) { + this.existingClientIds = existingClientIds; + } } diff --git a/src/main/java/com/percero/agents/sync/access/AccessManager.java b/src/main/java/com/percero/agents/sync/access/AccessManager.java deleted file mode 100644 index 7ebc7c9..0000000 --- a/src/main/java/com/percero/agents/sync/access/AccessManager.java +++ /dev/null @@ -1,1330 +0,0 @@ -package com.percero.agents.sync.access; - -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 org.apache.log4j.Logger; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; -import org.hibernate.criterion.Example; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -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.MappedClass; -import com.percero.agents.sync.metadata.MappedClassManagerFactory; -import com.percero.agents.sync.vo.AccessJournal; -import com.percero.agents.sync.vo.ClassIDPair; -import com.percero.agents.sync.vo.Client; -import com.percero.agents.sync.vo.DeleteJournal; -import com.percero.agents.sync.vo.UpdateJournal; -import com.percero.framework.vo.IPerceroObject; - -@Component -public class AccessManager implements IAccessManager { - - private static Logger log = Logger.getLogger(AccessManager.class); - - // TODO: Remove all AccessJournal objects for a User after they have been inactive for some amount of time. - // What should that amount of time be?... - - public AccessManager() { - } - - public void postClients() { - } - - @Autowired - SessionFactory sessionFactorySync; - public void setSessionFactorySync(SessionFactory value) { - sessionFactorySync = value; - } - - @Autowired - SessionFactory appSessionFactory; - public void setAppSessionFactory(SessionFactory value) { - appSessionFactory = value; - } - - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#createClient(java.lang.String, java.lang.Integer, java.lang.String) - */ - public void createClient(String clientId, String userId, String deviceType, String deviceId) throws Exception { - Session s = sessionFactorySync.openSession(); - - try { - Client theClient = new Client(); - theClient.setClientId(clientId); - theClient.setDeviceId(deviceId); - theClient.setBelongsToUserId(userId); - theClient.setDateCreated(new Date()); - theClient.setDeviceType(deviceType); - theClient.setIsLoggedIn(false); - Transaction tx = s.beginTransaction(); - tx.begin(); - s.save(theClient); - tx.commit(); - } catch(Exception e) { - log.error("Error creating client " + clientId + ", user " + userId.toString(), e); - } finally { - s.close(); - } - } - - @SuppressWarnings("unchecked") - public List getLoggedInClients() { - List result = null; - Session s = sessionFactorySync.openSession(); - - try { - Client theClient = new Client(); - theClient.setIsLoggedIn(true); - - Criteria criteriaClient = s.createCriteria(Client.class); - Example exampleClient = Example.create(theClient); - criteriaClient.add(exampleClient); - return (List) criteriaClient.list(); - } catch(Exception e) { - log.error("Error finding clients logged in", e); - result = null; - } finally { - s.close(); - } - - return result; - } - - @SuppressWarnings("unchecked") - public List getAllUserIDs() { - List result = null; - Session s = sessionFactorySync.openSession(); - - try { - Query query = s.createQuery("SELECT DISTINCT(belongsToUserId) FROM Client"); - return (List) query.list(); - } catch(Exception e) { - log.error("Error getting ALL User IDs", e); - result = null; - } finally { - s.close(); - } - - return result; - } - - // TODO: Implement getClientUserId - public String getClientUserId(String clientId) { - System.out.println("TODO: Implement getClientUserId"); - return null; - //return (String) redisDataStore.getValue(RedisKeyUtils.client(clientId)); - } - - - public Boolean findClientByClientIdUserId(String clientId, String userId) throws Exception { - Boolean result = false; - Session s = sessionFactorySync.openSession(); - - if (StringUtils.hasText(clientId) && StringUtils.hasText(userId)) { - try { - Client theClient = new Client(); - theClient.setClientId(clientId); - theClient.setBelongsToUserId(userId); - - Criteria criteriaClient = s.createCriteria(Client.class); - Example exampleClient = Example.create(theClient); - criteriaClient.add(exampleClient); - return criteriaClient.uniqueResult() != null; - } catch(Exception e) { - log.error("Error finding client " + clientId + ", user " + userId, e); - result = null; - } finally { - s.close(); - } - } - - return result; - } - - public Set findClientByUserIdDeviceId(String deviceId, String userId) throws Exception { - Set result = new HashSet(); - Session s = sessionFactorySync.openSession(); - - if (StringUtils.hasText(deviceId) && StringUtils.hasText(userId)) { - try { - Client theClient = new Client(); - theClient.setDeviceId(deviceId); - theClient.setBelongsToUserId(userId); - - Criteria criteriaClient = s.createCriteria(Client.class); - Example exampleClient = Example.create(theClient); - criteriaClient.add(exampleClient); - String clientId = ((Client) criteriaClient.uniqueResult()).getClientId(); - result.add(clientId); - } catch(Exception e) { - log.error("Error finding client for device " + deviceId + ", user " + userId, e); - result = null; - } finally { - s.close(); - } - } - - return result; - } - - public Boolean validateClientByClientId(String clientId) throws Exception { - return validateClientByClientId(clientId, true); - } - public Boolean validateClientByClientId(String clientId, Boolean setClientTimeouts) throws Exception { - return findClientByClientId(clientId); - } - public Boolean findClientByClientId(String clientId) throws Exception { - Boolean result = false; - - if (StringUtils.hasText(clientId)) { - Session s = sessionFactorySync.openSession(); - - try { - Client theClient = new Client(); - theClient.setClientId(clientId); - - Criteria criteriaClient = s.createCriteria(Client.class); - Example exampleClient = Example.create(theClient); - criteriaClient.add(exampleClient); - result = criteriaClient.uniqueResult() != null; - } catch(Exception e) { - log.error("Error finding client " + clientId, e); - result = null; - } finally { - s.close(); - } - } - - return result; - } - - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#registerClient(java.lang.String, java.lang.Integer) - */ - public void registerClient(String clientId, String userId, String deviceId) throws Exception { - registerClient(clientId, userId, deviceId, null); - } - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#registerClient(java.lang.String, java.lang.Integer) - */ - public void registerClient(String clientId, String userId, String deviceId, String deviceType) throws Exception { - Boolean isValidClient = findClientByClientIdUserId(clientId, userId); - if (!isValidClient) - createClient(clientId, userId, deviceType, deviceId); - - Session s = sessionFactorySync.openSession(); - - try { - Transaction tx = s.beginTransaction(); - tx.begin(); - Query q = s.createQuery("UPDATE Client c SET c.isLoggedIn=:isLoggedIn WHERE c.clientId=:clientId"); - q.setBoolean("isLoggedIn", true); - q.setString("clientId", clientId); - q.executeUpdate(); - tx.commit(); - } catch(Exception e) { - log.error("Error registering client " + clientId + ", user " + userId.toString(), e); - } finally { - s.close(); - } - } - - public Boolean hibernateClient(String clientId, String userId) throws Exception { - Boolean result = false; - Boolean isValidClient = findClientByClientIdUserId(clientId, userId); - if (isValidClient) { - - Session s = sessionFactorySync.openSession(); - - try { - Transaction tx = s.beginTransaction(); - tx.begin(); - Query q = s.createQuery("UPDATE Client c SET c.isLoggedIn=:isLoggedIn, c.dateLastLogout=:lastLogout WHERE c.clientId=:clientId"); - q.setBoolean("isLoggedIn", false); - q.setString("clientId", clientId); - q.setDate("lastLogout", new Date()); - tx.commit(); - result = true; - } catch(Exception e) { - log.error("Error hibernating client " + clientId + ", user " + userId.toString(), e); - result = false; - } finally { - s.close(); - } - } - - return result; - } - - // TODO: Implement - public void renameClient(String thePreviousClient, String clientId) { - System.out.println("TODO: Implement renameClient"); - } - - public Boolean upgradeClient(String clientId, String deviceId, String deviceType, String userId) throws Exception { - Boolean result = false; - Boolean theClientIsValid = findClientByClientIdUserId(clientId, userId); - String thePreviousClientId = null; - if (deviceId != null && deviceId.length() > 0) { - Set previousClientIds = findClientByUserIdDeviceId(userId, deviceId); - if (previousClientIds != null && !previousClientIds.isEmpty()) { - thePreviousClientId = previousClientIds.iterator().next(); - } -// thePreviousClientId = previousClientIds.findClientByUserIdDeviceId(userId, deviceId); - } - - if (!theClientIsValid && StringUtils.hasText(thePreviousClientId)) - clientId = thePreviousClientId; - - if (StringUtils.hasText(clientId)) { - Session s = sessionFactorySync.openSession(); - - try { - if (StringUtils.hasText(thePreviousClientId)) { - // If the previous client exists, then update previous client's clientId. - Client thePreviousClient = (Client) SyncHibernateUtils.cleanObject(s.get(Client.class, thePreviousClientId), s); - thePreviousClient.setClientId(clientId); - thePreviousClient.setDeviceType(deviceType); - thePreviousClient.setIsLoggedIn(true); - - Transaction tx = null; - if (!clientId.equals(thePreviousClient.getClientId())) { - tx = s.beginTransaction(); - tx.begin(); - - // Delete the Client, it was apparently only temporary. - // But, first update all UpdateJournals and DeleteJournals. - String updateJournalSql = "UPDATE UpdateJournal SET client=:previousClient WHERE client.clientId=:clientId"; - Query updateQuery = s.createQuery(updateJournalSql); - updateQuery.setEntity("previousClient", thePreviousClient); - updateQuery.setString("clientId", clientId); - updateQuery.executeUpdate(); - - String deleteJournalSql = "UPDATE DeleteJournal SET client=:previousClient WHERE client.clientId=:clientId"; - updateQuery = s.createQuery(deleteJournalSql); - updateQuery.setEntity("previousClient", thePreviousClient); - updateQuery.setString("clientId", clientId); - updateQuery.executeUpdate(); - - // Now delete theClient. - String deleteClient = "DELETE Client c WHERE c.clientId=:clientId"; - updateQuery = s.createQuery(deleteClient); - updateQuery.setString("clientId", clientId); - updateQuery.executeUpdate();; - tx.commit(); - } - - // Now save previousClient (can't save before deleting theClient due to unique constraint on clientId). - tx = s.beginTransaction(); - tx.begin(); - s.merge(thePreviousClient); - tx.commit(); - - result = true; - } - else { - // If the Previous client is null, then upgrade the Client. - Client theClient = (Client) SyncHibernateUtils.cleanObject(s.get(Client.class, clientId), s); - theClient.setDeviceType(deviceType); - Transaction tx = s.beginTransaction(); - tx.begin(); - s.merge(theClient); - tx.commit(); - result = true; - } - - } catch(Exception e) { - log.error("Error upgrading client " + clientId + ", user " + userId.toString(), e); - result = false; - } finally { - s.close(); - } - } - - return result; - } - - public Boolean saveClient(Client client) throws Exception { - Boolean result = false; - - if (client != null) { - Session s = sessionFactorySync.openSession(); - - try { - Transaction tx = null; - tx = s.beginTransaction(); - tx.begin(); - s.merge(client); - tx.commit(); - - result = true; - } catch(Exception e) { - log.error("Error saving client " + client.getID(), e); - result = false; - } finally { - s.close(); - } - } - - return result; - } - - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#logoutClient(java.lang.String) - */ - public void logoutClient(String clientId, Boolean pleaseDestroyClient) throws Exception { - Session s = sessionFactorySync.openSession(); - - try { - Client foundClient = null; - Query q = s.createQuery("FROM Client c WHERE c.clientId=:clientId"); - q.setString("clientId", clientId); - foundClient = (Client) q.uniqueResult(); - - //Client queryClient = new Client(); - //queryClient.setClientId(clientId); - //Criteria criteriaClient = s.createCriteria(Client.class); - //Example exampleClient = Example.create(queryClient); - //criteriaClient.add(exampleClient); - //foundClient = (Client) criteriaClient.uniqueResult(); - - if (foundClient != null) { - if (foundClient.getDeviceType() != null && foundClient.getDeviceType().equalsIgnoreCase(Client.PERSISTENT_TYPE)) { - // Persistent client, so set lastLogout date and isLoggedIn. - foundClient.setDateLastLogout(new Date()); - foundClient.setIsLoggedIn(false); - foundClient.setClientId(null); - Transaction tx = s.beginTransaction(); - tx.begin(); - s.merge(foundClient); - tx.commit(); - } else { - // Default is some sort of Non-Persistent client, so delete Client and ALL UpdateJournals. - Transaction tx = s.beginTransaction(); - tx.begin(); - String deleteTransJournalSql = "DELETE FROM TransactionJournal WHERE client=:client"; - Query deleteQuery = s.createQuery(deleteTransJournalSql); - deleteQuery.setEntity("client", foundClient); - deleteQuery.executeUpdate(); - - String deleteUpdateJournalSql = "DELETE FROM UpdateJournal WHERE client=:client"; - deleteQuery = s.createQuery(deleteUpdateJournalSql); - deleteQuery.setEntity("client", foundClient); - deleteQuery.executeUpdate(); - - String deleteDeleteJournalSql = "DELETE FROM DeleteJournal WHERE client=:client"; - deleteQuery = s.createQuery(deleteDeleteJournalSql); - deleteQuery.setEntity("client", foundClient); - deleteQuery.executeUpdate(); - - // Also delete client from Client table. - s.delete(foundClient); - tx.commit(); - } - } - } catch(Exception e) { - log.error("Error logging out client " + clientId, e); - } finally { - s.close(); - } - } - - // TODO: Implement getLoggedInUsers - public Collection getLoggedInUsers() { - System.out.println("TODO: Implement getLoggedInUsers"); - return null; - } - - // TODO: Implement - public void removeAccessJournalsByObject(ClassIDPair classIdPair) { - System.out.println("TODO: Implement removeAccessJournalsByObject"); - //redisDataStore.deleteKey(RedisKeyUtils.accessJournal(className, classId)); - } - - // TODO: Implement - public void removeUpdateJournalsByObject(ClassIDPair classIdPair) throws Exception { - System.out.println("TODO: Implement removeUpdateJournalsByObject"); - //redisDataStore.removeKeysValue(RedisKeyUtils.updateJournal("*"), RedisKeyUtils.classIdPair(className, classId)); - } - - // TODO: Implement - public void removeObjectModJournalsByObject(ClassIDPair classIdPair) { - System.out.println("TODO: Implement removeObjectModJournalsByObject"); - //redisDataStore.deleteKey(RedisKeyUtils.objectModJournal(className, classId)); - } - - // TODO: Implement - public void removeHistoricalObjectsByObject(ClassIDPair classIdPair) { - System.out.println("TODO: Implement removeHistoricalObjectsByObject"); - //redisDataStore.deleteKey(RedisKeyUtils.historicalObject(className, classId)); - } - - // TODO: Implement isNonPersistentClient - public Boolean isNonPersistentClient(String clientId) { - System.out.println("TODO: Implement isNonPersistentClient"); - return false; - //return redisDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId); - } - - // TODO: Implement deleteUpdateJournal - public Long deleteUpdateJournal(String clientId, String className, String classId) { - System.out.println("TODO: deleteUpdateJournal"); - return null; - //return redisDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(className, classId)); - } - - // TODO: deleteUpdateJournals - public void deleteUpdateJournals(String clientId, ClassIDPair[] objects) { - System.out.println("TODO: deleteUpdateJournals"); - //for(ClassIDPair nextObject : objects) { - // redisDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(nextObject.getClass().getCanonicalName(), nextObject.getID())); - //} - } - - // TODO: Implement deleteDeleteJournal - public Long deleteDeleteJournal(String clientId, String className, String classId) { - System.out.println("TODO: deleteDeleteJournal"); - return null; - //return redisDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(className, classId)); - } - - // TODO: deleteDeleteJournals - public void deleteDeleteJournals(String clientId, ClassIDPair[] objects) { - System.out.println("TODO: deleteDeleteJournals"); - //for(ClassIDPair nextObject : objects) { - // redisDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(nextObject.getClass().getCanonicalName(), nextObject.getID())); - //} - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - public Collection saveUpdateJournal(ClassIDPair pair, Collection listUserIds, Boolean guaranteeDelivery, String pusherClientId, Boolean sendToPusher) throws Exception { - Collection result = new ArrayList(); - - if (listUserIds != null && listUserIds.size() > 0) { - Session s = sessionFactorySync.openSession(); - - try { - Date currentDate = new Date(); - - // TODO: Since non-persistent, logged out clients are removed from the Client table, shouldn't - // this function simply query based on belongsToUserId and not need the additional - // (c.isLoggedIn OR s.deviceType) query? - String queryClientCountSql = "SELECT COUNT(c) AS clientCount FROM Client c WHERE c.belongsToUserId IN (:userIds)"; - Query clientCountQuery = s.createQuery(queryClientCountSql); - clientCountQuery.setParameterList("userIds", listUserIds); - - Long countClientsResult = (Long)clientCountQuery.uniqueResult(); - - if (((Long)countClientsResult).longValue() > 0) { - - List clientUpdateJournalList = null; - if (guaranteeDelivery) { - String updateJournalSelectClientsSql = "SELECT u FROM UpdateJournal u WHERE u.client.ID IN (SELECT c.ID FROM Client c WHERE c.belongsToUserId IN (:userIds)) AND " - + "u.classID=:classID AND u.className=:className"; - Query updateJournalSelectClientsQuery = s.createQuery(updateJournalSelectClientsSql); - updateJournalSelectClientsQuery.setParameterList("userIds", listUserIds); - updateJournalSelectClientsQuery.setString("classID", pair.getID()); - updateJournalSelectClientsQuery.setString("className", pair.getClassName()); - clientUpdateJournalList = updateJournalSelectClientsQuery.list(); - } else { - clientUpdateJournalList = new ArrayList(); - } - - if (clientUpdateJournalList != null && clientUpdateJournalList.size() > 0) { - // Update the dateModified in a batch Update command for better performance. - String updateUpdateJournalSql = "UPDATE UpdateJournal u SET u.dateModified=:dateModified " + - "WHERE u.client.ID IN (SELECT c.ID FROM Client c WHERE c.belongsToUserId IN (:userIds)) AND " - + "u.classID=:classID AND u.className=:className"; - Query updateUpdateJournalQuery = s.createQuery(updateUpdateJournalSql); - updateUpdateJournalQuery.setDate("dateModified", currentDate); - updateUpdateJournalQuery.setParameterList("userIds", listUserIds); - updateUpdateJournalQuery.setString("classID", pair.getID()); - updateUpdateJournalQuery.setString("className", pair.getClassName()); - updateUpdateJournalQuery.executeUpdate(); - - for(UpdateJournal nextUpdateJournal : clientUpdateJournalList) { - // Evict the record first so the update does not trigger a database update. - // Note: The update has already been done in the batch (see comment above). - s.evict(nextUpdateJournal); - nextUpdateJournal.setDateModified(currentDate); - result.add(nextUpdateJournal); - } - } - - String queryClientSql = "SELECT c FROM Client c WHERE c.belongsToUserId IN (:userIds) AND c.ID NOT IN (SELECT u.client.ID FROM UpdateJournal u " + - "WHERE u.classID=:classID AND u.className=:className)"; - Query clientQuery = s.createQuery(queryClientSql); - clientQuery.setParameterList("userIds", listUserIds); - clientQuery.setString("classID", pair.getID()); - clientQuery.setString("className", pair.getClassName()); - - List listClients = clientQuery.list(); - - Transaction tx = s.beginTransaction(); - - for(Client nextClient : listClients) { - if (!sendToPusher && StringUtils.hasText(pusherClientId)) { - // Don't send to pushing Client - if (nextClient.getID().equals(pusherClientId)) { - continue; - } - } - - UpdateJournal updateJournal = new UpdateJournal(); - // TODO: Use a class id map instead of class name for faster lookup. - // Use hash of full class name to generate ID? - updateJournal.setDateCreated(currentDate); - updateJournal.setDateModified(currentDate); - updateJournal.setClassID(pair.getID()); - updateJournal.setClassName(pair.getClassName()); - updateJournal.setClient(nextClient); - - if (guaranteeDelivery || (nextClient.getDeviceType() != null && nextClient.getDeviceType().equalsIgnoreCase(Client.PERSISTENT_TYPE))) { - try { - s.saveOrUpdate(updateJournal); - } catch(Exception e) { - log.warn("Error saving UpdateJournal: " + updateJournal.toString(), e); - } - } - - result.add(updateJournal); - } - - tx.commit(); - - result = (List) SyncHibernateUtils.cleanObject(result, s); - } - } catch(Exception e) { - log.error("Error saving UpdateJournal for " + pair.toString(), e); - } finally { - if (s != null && s.isOpen()) - s.close(); - } - } - - return result; - } - - public void saveUpdateJournalClients(ClassIDPair pair, Collection listClients, Boolean guaranteeDelivery, String pusherClientId, Boolean sendToPusher) throws Exception { - if (listClients != null && listClients.size() > 0) { - Session s = sessionFactorySync.openSession(); - - try { - Date currentDate = new Date(); - - Query selectUpdateJournal = s.createQuery("FROM UpdateJournal u WHERE u.client=:client AND " - + "u.classID=:classID AND u.className=:className"); - selectUpdateJournal.setString("classID", pair.getID()); - selectUpdateJournal.setString("className", pair.getClassName()); - - Transaction tx = s.beginTransaction(); - - int count = 0; - for(String nextClientId : listClients) { - if (!sendToPusher && StringUtils.hasText(pusherClientId)) { - // Don't send to pushing Client - if (nextClientId.equals(pusherClientId)) { - continue; - } - } - - Client nextClient = (Client) SyncHibernateUtils.loadObject(s.get(Client.class, nextClientId)); - - selectUpdateJournal.setParameter("client", nextClient); - - UpdateJournal uj = (UpdateJournal) selectUpdateJournal.uniqueResult(); - - if (uj != null) - { - uj.setDateModified(currentDate); - s.update(uj); - s.evict(uj); - uj.setClient(nextClient); // Make sure Client is fully loaded. - } - else - { - uj = new UpdateJournal(); - // TODO: Use a class id map instead of class name for faster lookup. - // Use hash of full class name to generate ID? - uj.setDateCreated(currentDate); - uj.setDateModified(currentDate); - uj.setClassID(pair.getID()); - uj.setClassName(pair.getClassName()); - uj.setClient(nextClient); - - if (guaranteeDelivery || (nextClient.getDeviceType() != null && nextClient.getDeviceType().equalsIgnoreCase(Client.PERSISTENT_TYPE))) - s.save(uj); - - } - - if (count > 0 && count % 1000 == 0) { - s.flush(); - s.clear(); - } - count++; - } - - tx.commit(); - - } catch(Exception e) { - log.error("Error saving UpdateJournal for " + pair.toString(), e); - } finally { - s.close(); - } - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - public Collection saveDeleteJournal(ClassIDPair pair, Collection listUserIds, Boolean guaranteeDelivery, String pusherClient, Boolean sendToPusher) throws Exception { - Collection result = new HashSet(); - - if (listUserIds != null && listUserIds.size() > 0) { - Session s = sessionFactorySync.openSession(); - - try { - Date currentDate = new Date(); - - // TODO: Since non-persistent, logged out clients are removed from the Client table, shouldn't - // this function simply query based on belongsToUserId and not need the additional - // (c.isLoggedIn OR s.deviceType) query? - String queryClientSql = "SELECT c FROM Client c WHERE c.belongsToUserId IN (:userIds) AND " - + "(c.isLoggedIn=:isLoggedIn OR c.deviceType=:deviceType)"; - Query clientQuery = s.createQuery(queryClientSql); - clientQuery.setParameterList("userIds", listUserIds); - clientQuery.setBoolean("isLoggedIn", true); - clientQuery.setString("deviceType", Client.PERSISTENT_TYPE); - - List listClients = clientQuery.list(); - - if (listClients != null && listClients.size() > 0) { - List clientDeleteJournalList = null; - - if (guaranteeDelivery) { - String deleteJournalSelectClientsSql = "SELECT d FROM DeleteJournal d WHERE d.client IN (:clients) AND " - + "d.classID=:classID AND d.className=:className"; - Query deleteJournalSelectClientsQuery = s.createQuery(deleteJournalSelectClientsSql); - deleteJournalSelectClientsQuery.setParameterList("clients", listClients); - deleteJournalSelectClientsQuery.setString("classID", pair.getID()); - deleteJournalSelectClientsQuery.setString("className", pair.getClassName()); - - clientDeleteJournalList = deleteJournalSelectClientsQuery.list(); - } else { - clientDeleteJournalList = new ArrayList(); - } - - Transaction tx = s.beginTransaction(); - tx.begin(); - if (clientDeleteJournalList != null && clientDeleteJournalList.size() > 0) { - // Update the dateModified in a batch Delete command for better performance. - String deleteUpdateJournalSql = "UPDATE DeleteJournal d SET d.dateModified=:dateModified WHERE d IN (:deleteJournals)"; - Query deleteUpdateJournalQuery = s.createQuery(deleteUpdateJournalSql); - deleteUpdateJournalQuery.setDate("dateModified", currentDate); - deleteUpdateJournalQuery.setParameterList("deleteJournals", clientDeleteJournalList); - deleteUpdateJournalQuery.executeUpdate(); - - for(DeleteJournal nextDeleteJournal : clientDeleteJournalList) { - // Evict the record first so the update does not trigger a database update. - // Note: The delete has already been done in the batch (see comment above). - s.evict(nextDeleteJournal); - nextDeleteJournal.setDateModified(currentDate); - - result.add(nextDeleteJournal.getClient().getClientId()); - - if ( listClients.contains(nextDeleteJournal.getClient()) ) { - listClients.remove(nextDeleteJournal.getClient()); - } - } - } - - for(Client nextClient : listClients) { - // Only store updates for LoggedIn and/or Persistent Clients. - if (nextClient.getIsLoggedIn() || (nextClient.getDeviceType() != null && nextClient.getDeviceType().equalsIgnoreCase(Client.PERSISTENT_TYPE))) { - if (!sendToPusher && pusherClient != null) { - // Don't send to pushing Client - if (nextClient.getID().equals(pusherClient)) { - continue; - } - } - - DeleteJournal deleteJournal = new DeleteJournal(); - // TODO: Use a class id map instead of class name for faster lookup. - // Use hash of full class name to generate ID? - deleteJournal.setDateCreated(currentDate); - deleteJournal.setDateModified(currentDate); - deleteJournal.setClassID(pair.getID()); - deleteJournal.setClassName(pair.getClassName()); - deleteJournal.setClient(nextClient); - - if (guaranteeDelivery || (nextClient.getDeviceType() != null && nextClient.getDeviceType().equalsIgnoreCase(Client.PERSISTENT_TYPE))) - s.save(deleteJournal); - - result.add(nextClient.getClientId()); - } - } - tx.commit(); - - result = (List) SyncHibernateUtils.cleanObject(result, s); - } - } catch(Exception e) { - log.error("Error saving DeleteJournal for " + pair.toString(), e); - } finally { - s.close(); - } - } - - return result; - } - - public boolean saveAccessJournal(List classIdPairs, String userId) throws Exception { - - boolean saveAccessJournalFailure = false; - for(ClassIDPair nextObject : classIdPairs) { - if (!saveAccessJournal(nextObject, userId)) - saveAccessJournalFailure = true; - } - - return !saveAccessJournalFailure; - } - - @SuppressWarnings("rawtypes") - public boolean saveAccessJournal(ClassIDPair pair, String userId) throws Exception { - - Session s = sessionFactorySync.openSession(); - - try { - AccessJournal accessJournal = new AccessJournal(); - // TODO: Use a class id map instead of class name for faster lookup. - // Use hash of full class name to generate ID? - accessJournal.setClassName(pair.getClassName()); - accessJournal.setClassID(pair.getID()); - accessJournal.setUserID(userId); - - Criteria criteria = s.createCriteria(AccessJournal.class); - AssociationExample example = AssociationExample.create(accessJournal); - BaseDataObjectPropertySelector propertySelector = new BaseDataObjectPropertySelector(null); - example.setPropertySelector(propertySelector); - criteria.add(example); - - List result = criteria.list(); - - if (result == null || result.isEmpty()) { - // Attempt direct insert. Don't care if duplicate index error. Just care that record is in database. - Transaction tx = s.beginTransaction(); - tx.begin(); - s.save(accessJournal); - tx.commit(); - } - - return true; - } catch(Exception e) { - // Unable to INSERT AccessJournal. Must already exist. - return true; - } finally { - s.close(); - } - } - - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#getObjectAccessJournals(java.lang.String, java.lang.Integer) - */ - @SuppressWarnings("unchecked") - public List getObjectAccessJournals(String className, String classId) throws Exception { - List result = new ArrayList(); - Session s = sessionFactorySync.openSession(); - - try { - // TODO: Use a class id map instead of class name for faster lookup. - // Use hash of full class name to generate ID? - String selectAccessJournalSql = "SELECT DISTINCT(aj.userID) FROM AccessJournal aj WHERE className=:className " - + "AND (classID='0' OR classID=:classID)"; - Query selectAccessJournalQuery = s.createQuery(selectAccessJournalSql); - selectAccessJournalQuery.setString("className", className); - selectAccessJournalQuery.setString("classID", classId); - - List userIdList = selectAccessJournalQuery.list(); - result = checkUserListAccessRights(userIdList, className, classId); - } catch(Exception e) { - log.error("Error getting accessJournal for Object " + className + "(" + classId + ")", e); - } finally { - s.close(); - } - - 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>(); - Session s = sessionFactorySync.openSession(); - - // Return here if no classIdPairs have actually been supplied. - if (classIdPairs.size() == 0) - return result; - - try { - // Use hash of full class name to generate ID? - String selectAccessJournalSql = "SELECT c FROM Client c WHERE c.belongsToUserId IN (SELECT DISTINCT(aj.userID) FROM AccessJournal aj WHERE"; - Iterator itrClassIdPairs = classIdPairs.iterator(); - int i = 0; - while(itrClassIdPairs.hasNext()) { - ClassIDPair nextObject = itrClassIdPairs.next(); - if (i > 0) - selectAccessJournalSql += " OR"; - selectAccessJournalSql += " (aj.className='" + nextObject.getClassName() + "' " - + "AND (aj.classID='0' OR aj.classID='" + nextObject.getID() + "'))"; - - i++; - } - selectAccessJournalSql += ") ORDER BY c.belongsToUserId"; - Query selectAccessJournalQuery = s.createQuery(selectAccessJournalSql); - - List clientsList = selectAccessJournalQuery.list(); - for(Client nextClient : clientsList) { - Collection nextClientList = result.get(nextClient.getBelongsToUserId()); - if (nextClientList == null) { - nextClientList = new ArrayList(); - result.put(nextClient.getBelongsToUserId(), nextClientList); - } - nextClientList.add(nextClient.getClientId()); - } - - //result = checkUserListAccessRights(userIdList, className, classId); - } catch(Exception e) { - log.error("Error getting client accesses", e); - } finally { - s.close(); - } - - return result; - } - - public List checkUserListAccessRights(List userIdList, String className, String classId) throws Exception { - List result = new ArrayList(); - Session appSession = appSessionFactory.openSession(); - - try { - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(className); - Query query = null; - - boolean isValidReadQuery = false; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - isValidReadQuery = true; - query = appSession.createQuery(mappedClass.getReadQuery().getQuery()); - } - } - - for(String nextUserId : userIdList) { - try { - 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.getQueryString(), classId, nextUserId); - Number readFilterResult = (Number) query.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - - if (hasAccess) - result.add(nextUserId.toString()); - } catch(Exception e) { - log.warn("Error getting Object Access Journals", e); - } - } - } catch(Exception e) { - log.error("Error checking User AccessRights for " + className + "(" + classId + ")", e); - } finally { - if (appSession != null && appSession.isOpen()) - appSession.close(); - } - - return result; - } - - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#getUserAccessJournals(java.lang.Integer) - */ - @SuppressWarnings("unchecked") - public List getUserAccessJournals(String userId) throws Exception { - List result = null; - Session s = sessionFactorySync.openSession(); - - try { - // TODO: Use a class id map instead of class name for faster lookup. - // Use hash of full class name to generate ID? - String accessJournalSql = "SELECT aj FROM AccessJournal aj WHERE userID=:userID"; - Query accessJournalQuery = s.createQuery(accessJournalSql); - accessJournalQuery.setInteger("userID", Integer.parseInt(userId)); - result = accessJournalQuery.list(); - } catch(Exception e) { - log.error("Error getting accessJournal for user " + userId, e); - } finally { - s.close(); - } - - return result; - } - - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#getClientUpdateJournals(java.lang.String) - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - public Collection getClientUpdateJournals(String clientId, Boolean loggedInOnly) throws Exception { - Collection result = new ArrayList(); - Session s = sessionFactorySync.openSession(); - - try { - String updateJournalSelect = "SELECT u FROM UpdateJournal u WHERE u.client.clientId=:clientId";// IN (SELECT c FROM Client c WHERE c.clientId=:clientId)"; - Query updateJournalQuery = s.createQuery(updateJournalSelect); - updateJournalQuery.setString("clientId", clientId); - - List updateJournalList = (List) SyncHibernateUtils.cleanObject(updateJournalQuery.list(), s); - - if (loggedInOnly) { - Iterator itrResult = updateJournalList.iterator(); - while(itrResult.hasNext()) { - UpdateJournal uj = (UpdateJournal) itrResult.next(); - if (!uj.getClient().getIsLoggedIn()) { - itrResult.remove(); - } - } - } - } catch(Exception e) { - log.error("Error getting updateJournals for client " + clientId, e); - } finally { - s.close(); - } - - return result; - } - - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#getClientDeleteJournals(java.lang.String) - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - public Collection getClientDeleteJournals(String clientId, Boolean loggedInOnly) throws Exception { - List result = new ArrayList(); - Session s = sessionFactorySync.openSession(); - - try { - String deleteJournalSelect = "SELECT d FROM DeleteJournal d WHERE d.client IN (SELECT c FROM Client c WHERE c.clientId=:clientId"; - if (loggedInOnly) { - deleteJournalSelect += " AND c.isLoggedIn=:isLoggedIn"; - } - deleteJournalSelect += ")"; - Query deleteJournalQuery = s.createQuery(deleteJournalSelect); - deleteJournalQuery.setString("clientId", clientId); - if (loggedInOnly) { - deleteJournalQuery.setBoolean("isLoggedIn", true); - } - - result = (List) SyncHibernateUtils.cleanObject(deleteJournalQuery.list(), s); - } catch(Exception e) { - log.error("Error getting deleteJournals for client " + clientId, e); - } finally { - s.close(); - } - - return result; - } - - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#removeUpdateJournals(java.util.List) - */ - public void removeUpdateJournals(List updateJournalsToRemove) throws Exception { - Session s = sessionFactorySync.openSession(); - - try { - Transaction tx = s.beginTransaction(); - tx.begin(); - String deleteUpdateJournalSql = "DELETE FROM UpdateJournal uj WHERE uj IN (:updateJournals)"; - Query deleteUpdateJournalQuery = s.createQuery(deleteUpdateJournalSql); - deleteUpdateJournalQuery.setParameterList("updateJournals", updateJournalsToRemove); - deleteUpdateJournalQuery.executeUpdate(); - tx.commit(); - } catch(Exception e) { - log.error("Error removing updateJournals", e); - } finally { - s.close(); - } - } - - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#removeUpdateJournalsByObject(IPerceroObject) - */ - public void removeUpdateJournalsByObject(IPerceroObject object) throws Exception { - Session s = sessionFactorySync.openSession(); - - try { - Transaction tx = s.beginTransaction(); - tx.begin(); - String deleteUpdateJournalSql = "DELETE FROM UpdateJournal uj WHERE uj.className=:className AND uj.classID=:classId"; - Query deleteUpdateJournalQuery = s.createQuery(deleteUpdateJournalSql); - deleteUpdateJournalQuery.setString("className", object.getClass().getName()); - deleteUpdateJournalQuery.setString("classId", object.getID()); - deleteUpdateJournalQuery.executeUpdate(); - tx.commit(); - } catch(Exception e) { - log.error("Error removing updateJournals", e); - } finally { - s.close(); - } - } - - public void addWatcherField(ClassIDPair classIdPair, String fieldName, - Collection collection) { - // TODO Auto-generated method stub - - } - -// public Collection getWatcherFields(ClassIDPair classIdPair, -// String fieldName) { -// // TODO Auto-generated method stub -// return null; -// } - - public void addWatcherClient(ClassIDPair classIdPair, - String fieldName, String clientId) { - // TODO Auto-generated method stub - - } - - public void updateWatcherFields(ClassIDPair classIdPair, - String fieldName, Collection fieldsToWatch) { - // TODO Auto-generated method stub - - } - - public void saveChangeWatcherResult(ClassIDPair classIdPaird, - String fieldName, Object result) { - // TODO Auto-generated method stub - - } - - public Object getChangeWatcherResult(ClassIDPair classIdPair, - String fieldName) { - // TODO Auto-generated method stub - return null; - } - - public void checkChangeWatchers(ClassIDPair classIdPair) { - // TODO Auto-generated method stub - - } - - public void checkChangeWatchers(ClassIDPair classIdPair, - String fieldName) { - // TODO Auto-generated method stub - - } - - public Boolean getChangeWatcherResultExists(ClassIDPair classIdPair, String fieldName) { - // TODO Auto-generated method stub - return false; - } - - public Boolean getChangeWatcherResultExists(ClassIDPair classIdPair, String fieldName, String[] params) { - // TODO Auto-generated method stub - return null; - } - - public Object getChangeWatcherResult(ClassIDPair classIdPair, String fieldName, String[] params) { - // TODO Auto-generated method stub - return null; - } - - public void addWatcherClient(ClassIDPair classIdPair, - String fieldName, String clientId, String[] params) { - // TODO Auto-generated method stub - - } - - public void updateWatcherFields(ClassIDPair classIdPair, - String fieldName, Collection fieldsToWatch, String[] params) { - // TODO Auto-generated method stub - - } - - public void saveChangeWatcherResult(ClassIDPair classIdPair, - String fieldName, Object result, String[] params) { - // TODO Auto-generated method stub - - } - - public void addWatcherField(ClassIDPair classIdPair, String fieldName, - Collection collection, String[] params) { - // TODO Auto-generated method stub - - } - - public void checkChangeWatchers(ClassIDPair classIdPair, - String fieldName, String[] params, IPerceroObject oldValue) { - // TODO Auto-generated method stub - - } - - @Override - public void removeChangeWatchersByObject(ClassIDPair classIdPair) { - // TODO Auto-generated method stub - - } - - @Override - public void checkChangeWatchers(ClassIDPair classIdPair, - String[] fieldNames, String[] params, IPerceroObject oldValue) { - // TODO Auto-generated method stub - - } - - @Override - public void recalculateChangeWatcher(String changeWatcherId, IPerceroObject oldValue) { - // TODO Auto-generated method stub - - } - - @Override - public Long getChangeWatcherResultTimestamp(ClassIDPair classIdPair, - String fieldName, String[] params) { - // TODO Auto-generated method stub - return null; - } - - @Override - public void saveDeleteJournalClients(ClassIDPair pair, - Collection clientIds, Boolean guaranteeDelivery, - String pusherClient, Boolean sendToPusher) throws Exception { - // TODO Auto-generated method stub - - } - - @Override - public boolean saveAccessJournal(ClassIDPair classIdPair, String userId, - String clientId) throws Exception { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean saveAccessJournal(List classIdPairs, - String userId, String clientId) throws Exception { - // TODO Auto-generated method stub - return false; - } - - @Override - public void destroyClient(String clientId) { - // TODO Auto-generated method stub - - } - - @Override - public Set validateClientsIncludeFromDeviceHistory(Map clientDevices) - throws Exception { - // TODO Auto-generated method stub - return null; - } - - @Override - public Set validateClients(Collection clientIds) - throws Exception { - // TODO Auto-generated method stub - return null; - } - - @Override - public String validateAndRetrieveCurrentClientId(String clientId, - String deviceId) { - // TODO Auto-generated method stub - 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 - - } - - @Override - public void checkAndRemoveChangeWatchers(ClassIDPair classIdPair, String[] fieldNames, String[] params, - IPerceroObject oldValue) { - // TODO Auto-generated method stub - - } - - /* (non-Javadoc) - * @see com.com.percero.agents.sync.services.IAccessManager#removeDeleteJournals(java.util.List) - * - public boolean removeDeleteJournals(List deleteJournalsToRemove) throws Exception { - boolean result = false; - Session s = sessionFactorySync.openSession(); - - try { - Transaction tx = s.beginTransaction(); - tx.begin(); - String deleteDeleteJournalSql = "DELETE FROM DeleteJournal dj WHERE dj IN (:deleteJournals)"; - Query deleteDeleteJournalQuery = s.createQuery(deleteDeleteJournalSql); - deleteDeleteJournalQuery.setParameterList("deleteJournals", deleteJournalsToRemove); - deleteDeleteJournalQuery.executeUpdate(); - tx.commit(); - - result = true; - } catch(Exception e) { - log.error("Error removing deleteJournals", e); - } finally { - s.close(); - } - - return result; - }*/ -} 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 26989b8..0b59d2c 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -14,13 +14,11 @@ import java.util.TreeMap; import java.util.concurrent.TimeUnit; -import com.percero.framework.vo.IPerceroObject; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; @@ -34,8 +32,8 @@ import com.percero.agents.sync.services.IPushSyncHelper; import com.percero.agents.sync.vo.ClassIDPair; import com.percero.agents.sync.vo.Client; +import com.percero.framework.vo.IPerceroObject; -@Component public class RedisAccessManager implements IAccessManager { private static Logger log = Logger.getLogger(RedisAccessManager.class); @@ -285,7 +283,7 @@ public Boolean upgradeClient(String clientId, String deviceId, String deviceType // Make sure this is a valid client. Boolean isValidClient = findClientByClientIdUserId(clientId, userId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "Unable to upgradeClient", clientId); Set previousClientIds = null; if (deviceId != null && deviceId.length() > 0) { diff --git a/src/main/java/com/percero/agents/sync/aspects/ValidClientAspect.java b/src/main/java/com/percero/agents/sync/aspects/ValidClientAspect.java index a8a496e..18b92fe 100644 --- a/src/main/java/com/percero/agents/sync/aspects/ValidClientAspect.java +++ b/src/main/java/com/percero/agents/sync/aspects/ValidClientAspect.java @@ -21,6 +21,6 @@ public void assertValidClient(String clientId) throws Exception { //String clientId = ""; Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); } } 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 9b0ba3e..2a60483 100644 --- a/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java +++ b/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java @@ -3,6 +3,7 @@ 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; @@ -13,7 +14,7 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; -import com.percero.agents.sync.hibernate.SyncHibernateUtils; +import com.percero.agents.sync.exceptions.SyncException; import com.percero.agents.sync.metadata.IMappedClassManager; import com.percero.agents.sync.metadata.MappedClass; import com.percero.agents.sync.metadata.MappedClassManagerFactory; @@ -340,7 +341,7 @@ public void pushChangeWatcherUpdate(Collection clientIds, ClassIDPair cl //if (value instanceof BaseDataObject) { String userId = accessManager.getClientUserId(clientId); // Clean the value if it is a framework object. - value = SyncHibernateUtils.cleanObject(value, null, userId); + value = cleanChangeWatcherValue(value, userId); //} pushUpdateResponse.setValue(value); pushUpdateResponse.setClientId(clientId); @@ -353,6 +354,37 @@ public void pushChangeWatcherUpdate(Collection clientIds, ClassIDPair cl } } } + /** + * @param value + * @param userId + * @return + * @throws SyncException + */ + private Object cleanChangeWatcherValue(Object value, String userId) throws SyncException { + if (value instanceof IPerceroObject) { + MappedClass mc = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(value.getClass().getCanonicalName()); + value = mc.getDataProvider().cleanObject((IPerceroObject) value, userId); + } + else if (value instanceof List) { + // We know this is a list, so best attempt is to get class of first object in list and use that to get the corresponding mapped class. + List listValue = (List) value; + if (!listValue.isEmpty()) { + Object firstListValue = listValue.get(0); + if (firstListValue instanceof IPerceroObject) { + MappedClass mc = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(firstListValue.getClass().getCanonicalName()); + try { + // No guarantee this will work, so wrap in try/catch. + value = mc.getDataProvider().cleanObject((List) value, userId); + } + catch(Exception e) { + // Do nothing. + log.debug("Unable to clean change watcher value", e); + } + } + } + } + return value; + } public void pushChangeWatcherUpdate(String clientId, ClassIDPair classIdPair, String fieldName, String[] params, Object value) { if (StringUtils.hasText(clientId)) { try { @@ -364,7 +396,7 @@ public void pushChangeWatcherUpdate(String clientId, ClassIDPair classIdPair, St 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); + value = cleanChangeWatcherValue(value, userId); } pushUpdateResponse.setValue(value); diff --git a/src/main/java/com/percero/agents/sync/dao/ActiveStackMySQLDialect.java b/src/main/java/com/percero/agents/sync/dao/ActiveStackMySQLDialect.java index deb38aa..c774236 100644 --- a/src/main/java/com/percero/agents/sync/dao/ActiveStackMySQLDialect.java +++ b/src/main/java/com/percero/agents/sync/dao/ActiveStackMySQLDialect.java @@ -2,15 +2,15 @@ import java.sql.Types; -import org.hibernate.Hibernate; import org.hibernate.dialect.MySQLDialect; +import org.hibernate.type.TextType; public class ActiveStackMySQLDialect extends MySQLDialect { public ActiveStackMySQLDialect() { super(); - registerHibernateType(Types.LONGVARCHAR, Hibernate.TEXT.getName()); + registerHibernateType(Types.LONGVARCHAR, TextType.INSTANCE.getName()); } } diff --git a/src/main/java/com/percero/agents/sync/dao/DAORegistry.java b/src/main/java/com/percero/agents/sync/dao/DAORegistry.java index c1401ee..3c63088 100644 --- a/src/main/java/com/percero/agents/sync/dao/DAORegistry.java +++ b/src/main/java/com/percero/agents/sync/dao/DAORegistry.java @@ -24,6 +24,10 @@ public DAORegistry() { @SuppressWarnings({ "unchecked" }) private Map> dataAccessObjects = Collections.synchronizedMap(new HashMap>()); + public Map> getDataAccessObjects() { + return dataAccessObjects; + } + public void registerDataAccessObject(String name, IDataAccessObject dataAccessObject) { dataAccessObjects.put(name, dataAccessObject); } diff --git a/src/main/java/com/percero/agents/sync/exceptions/ClientException.java b/src/main/java/com/percero/agents/sync/exceptions/ClientException.java index d79246d..6dfe459 100644 --- a/src/main/java/com/percero/agents/sync/exceptions/ClientException.java +++ b/src/main/java/com/percero/agents/sync/exceptions/ClientException.java @@ -13,16 +13,23 @@ public ClientException(String name, Integer code, String desc, Throwable t) { super(name, code, desc, t); } - public ClientException(String name, Integer code, String desc) { + public ClientException(String name, Integer code, String desc, String clientId) { super(name, code, desc); - } - - public ClientException(String name, Integer code) { - super(name, code); + this.clientId = clientId; } public ClientException() { super(); } + + private String clientId; + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } } 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 cefef5e..e1cca81 100644 --- a/src/main/java/com/percero/agents/sync/exceptions/SyncDataException.java +++ b/src/main/java/com/percero/agents/sync/exceptions/SyncDataException.java @@ -31,6 +31,10 @@ public SyncDataException(String name, Integer code, String desc) { super(name, code, desc); } + public SyncDataException(String name, Integer code, Throwable t) { + super(name, code, t); + } + public SyncDataException(String name, Integer code) { super(name, code); } 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 4501f33..04fcf9c 100644 --- a/src/main/java/com/percero/agents/sync/exceptions/SyncException.java +++ b/src/main/java/com/percero/agents/sync/exceptions/SyncException.java @@ -21,6 +21,7 @@ public class SyncException extends Exception { public static final String METHOD_NOT_IMPLEMENTED = "methodNotImplemented"; public static final Integer METHOD_NOT_IMPLEMENTED_CODE = -106; + public static final Integer PROCESS_ERROR_CODE = -1000; public SyncException(String name, Integer code, String desc, Throwable t) { super(desc, t); @@ -40,6 +41,12 @@ public SyncException(String name, Integer code) { this.setCode(code); } + public SyncException(String name, Integer code, Throwable t) { + super(t); + this.setName(name); + this.setCode(code); + } + public SyncException(Throwable t) { super(t); } diff --git a/src/main/java/com/percero/agents/sync/helpers/PostCreateHelper.java b/src/main/java/com/percero/agents/sync/helpers/PostCreateHelper.java index 5f72b5c..8946866 100644 --- a/src/main/java/com/percero/agents/sync/helpers/PostCreateHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/PostCreateHelper.java @@ -1,5 +1,6 @@ package com.percero.agents.sync.helpers; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -81,19 +82,31 @@ public void postCreateObject(IPerceroObject perceroObject, String pusherUserId, if (pusherUserId != null && pusherUserId.length() > 0) accessManager.saveAccessJournal(pair, pusherUserId, pusherClientId); - // Sending an empty List as the ChangedFields parameter will cause the PostPutHelper to NOT check access - // managers for each field since it is impossible for change watchers to already exist for this new - // object. - postPutHelper.postPutObject(pair, pusherUserId, pusherClientId, pushToUser, new HashMap>()); - // For each association, update push the associated objects. IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(pair.getClassName()); + // Sending an empty List as the ChangedFields parameter will cause the PostPutHelper to NOT check access + // managers for each field since it is impossible for change watchers to already exist for this new + // object. + + // Since this object has been deleted, ALL fields have changed. + Iterator itrChangedFields = mappedClass.externalizableFields.iterator(); + Map> changedFields = new HashMap>(1); + Collection changedMappedFields = new ArrayList(mappedClass.externalizableFields.size()); + while (itrChangedFields.hasNext()) { + MappedField nextChangedField = itrChangedFields.next(); + changedMappedFields.add(nextChangedField); + } + + postPutHelper.postPutObject(pair, pusherUserId, pusherClientId, pushToUser, changedFields); + Map> changedObjects = new HashMap>(); - for(MappedFieldPerceroObject nextMappedField : mappedClass.externalizablePerceroObjectFields) { + // The only relationship fields that could have changed are source relationship fields + for(MappedFieldPerceroObject nextMappedField : mappedClass.getSourceMappedFields()) { try { + // We only care about two-way relationships. if (nextMappedField.getReverseMappedField() != null) { IPerceroObject fieldValue = (IPerceroObject) nextMappedField.getValue(perceroObject); if (fieldValue != null) { 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 6915fcc..030f813 100644 --- a/src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/PostDeleteHelper.java @@ -1,6 +1,10 @@ package com.percero.agents.sync.helpers; import com.percero.agents.sync.access.IAccessManager; +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.services.IPushSyncHelper; import com.percero.agents.sync.services.ISyncAgentService; import com.percero.agents.sync.vo.ClassIDPair; @@ -14,7 +18,11 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; @Component public class PostDeleteHelper { @@ -62,10 +70,7 @@ 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); @@ -88,6 +93,32 @@ public void postDeleteObject(ClassIDPair pair, String pusherUserId, String pushe /*Collection deleteJournals = */accessManager.saveDeleteJournalClients(pair, clientIds, guaranteeUpdateDelivery, pusherClientId, pushToUser); pushObjectDeleteJournals(clientIds, pair.getClassName(), pair.getID()); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(pair.getClassName()); + if (mappedClass != null) { + // Since this object has been deleted, ALL fields have changed. + Iterator itrChangedFields = mappedClass.externalizableFields.iterator(); + String[] fieldNames = new String[mappedClass.externalizableFields.size()]; + int i = 0; + while (itrChangedFields.hasNext()) { + MappedField nextChangedField = itrChangedFields.next(); + fieldNames[i] = nextChangedField.getField().getName(); + i++; + } + pushSyncHelper.enqueueCheckChangeWatcher(pair, fieldNames, null, theObject); + + Map objectsToUpdate = mappedClass.getRelatedClassIdPairMappedFieldMap(theObject, false); + 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(), pusherUserId, pusherClientId, true, changedFields); + } + } } protected void pushObjectDeleteJournals(Collection clientIds, String className, String classId) { 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 41607ea..538322b 100644 --- a/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java @@ -80,21 +80,12 @@ public void postPutObject(ClassIDPair pair, String pusherUserId, String pusherCl break; } } -// Iterator itrChangedFieldsKeys = changedFields.keySet().iterator(); -// while (itrChangedFieldsKeys.hasNext()) { -// ClassIDPair nextPair = itrChangedFieldsKeys.next(); -// if (nextPair.equals(pair)) { -// pairChangedFields = changedFields.get(nextPair); -// break; -// } -// } } pushObjectUpdateJournals(clientIds, pair, pairChangedFields); // Now run past the ChangeWatcher. if (changedFields == null || changedFields.isEmpty()) { - enqueueCheckChangeWatcher(pair, null, null, oldValue); -// accessManager.checkChangeWatchers(pair, null, null); + pushSyncHelper.enqueueCheckChangeWatcher(pair, null, null, oldValue); } else { // TODO: Need to somehow aggregate changes per client/object. @@ -127,42 +118,12 @@ public void postPutObject(ClassIDPair pair, String pusherUserId, String pusherCl } // Swap out inline processing for a worker queue - enqueueCheckChangeWatcher(thePair, fieldNames, null, oldValue); -// accessManager.checkChangeWatchers(thePair, fieldNames, null); + pushSyncHelper.enqueueCheckChangeWatcher(thePair, fieldNames, null, oldValue); } } - -// Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); -// while (itrChangedFieldKeyset.hasNext()) { -// ClassIDPair thePair = itrChangedFieldKeyset.next(); -// Collection changedMappedFields = changedFields.get(thePair); -// Iterator itrChangedFields = changedMappedFields.iterator(); -// String[] fieldNames = new String[changedMappedFields.size()]; -// int i = 0; -// while (itrChangedFields.hasNext()) { -// MappedField nextChangedField = itrChangedFields.next(); -// fieldNames[i] = nextChangedField.getField().getName(); -// i++; -// } -// accessManager.checkChangeWatchers(thePair, fieldNames, null); -// } } } - public void enqueueCheckChangeWatcher(ClassIDPair classIDPair, String[] fieldNames, String[] params, IPerceroObject oldValue){ - CheckChangeWatcherMessage message = new CheckChangeWatcherMessage(); - message.classIDPair = classIDPair; - message.fieldNames = fieldNames; - message.params = params; - if(oldValue != null) - message.oldValueJson = ((BaseDataObject)oldValue).toJson(); - template.convertAndSend("checkChangeWatcher", message); - } - - public void enqueueCheckChangeWatcher(ClassIDPair classIDPair, String[] fieldNames, String[] params){ - enqueueCheckChangeWatcher(classIDPair, fieldNames, params, null); - } - public void pushObjectUpdateJournals(Collection clientIds, ClassIDPair classIdPair, Collection changedFields) { if (classIdPair != null && clientIds != null && !clientIds.isEmpty()) { IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); @@ -237,74 +198,9 @@ public void pushObjectUpdateJournals(Collection clientIds, ClassIDPair c pushUpdateResponse.getObjectList().add(object); pushSyncHelper.pushSyncResponseToClients(pushUpdateResponse, userClients); } - -// try { -// PushUpdateResponse pushUpdateResponse = new PushUpdateResponse(); -// pushUpdateResponse.setObjectList(new ArrayList()); -// -// pushUpdateResponse.setClientId(nextClientId); -// -// // Need to get version of this object appropriate for this client. -// Object object = dataProvider.findById(classIdPair, userId); -// -// if (object != null) { -// pushUpdateResponse.getObjectList().add((BaseDataObject) object); -// -// // Add changed fields names -// if (changedFields != null) { -// Iterator itrChangedFields = changedFields.iterator(); -// while (itrChangedFields.hasNext()) { -// MappedField nextChangedField = itrChangedFields.next(); -// pushUpdateResponse.addUpdatedField(nextChangedField.getField().getName()); -// } -// } -// -// pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, nextClientId); -// } -// } catch(Exception e) { -// log.error("Error pushing Object Update Journal to clients", e); -// } } } } } -// public void pushClientUpdateJournals(Map> clientUpdates) { -// -// Iterator>> itrClientUpdatesEntrySet = clientUpdates.entrySet().iterator(); -// while (itrClientUpdatesEntrySet.hasNext()) { -// Map.Entry> nextEntry = itrClientUpdatesEntrySet.next(); -// String nextClientId = nextEntry.getKey(); -// Set pairs = nextEntry.getValue(); -// -// String userId = accessManager.getClientUserId(nextClientId); -// List objectList = new ArrayList(); -// -// PushUpdateResponse pushUpdateResponse = new PushUpdateResponse(); -// pushUpdateResponse.setObjectList(objectList); -// pushUpdateResponse.setClientId(nextClientId); -// -// Iterator itrPairs = pairs.iterator(); -// while (itrPairs.hasNext()) { -// try { -// ClassIDPair pair = itrPairs.next(); -// -// IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); -// MappedClass mc = mcm.getMappedClassByClassName(pair.getClassName()); -// IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mc.dataProviderName); -// BaseDataObject perceroObject = (BaseDataObject) dataProvider.findById(pair, userId); -// -// if (perceroObject != null) { -// objectList.add(perceroObject); -// } -// } catch(Exception e) { -// log.error("Error pushing Object Update Journal to client " + nextClientId, e); -// } -// } -// -// if (!objectList.isEmpty()) { -// pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, nextClientId); -// } -// } -// } } diff --git a/src/main/java/com/percero/agents/sync/hibernate/AssociationExample.java b/src/main/java/com/percero/agents/sync/hibernate/AssociationExample.java deleted file mode 100644 index a727942..0000000 --- a/src/main/java/com/percero/agents/sync/hibernate/AssociationExample.java +++ /dev/null @@ -1,345 +0,0 @@ -package com.percero.agents.sync.hibernate; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.hibernate.Criteria; -import org.hibernate.EntityMode; -import org.hibernate.HibernateException; -import org.hibernate.criterion.CriteriaQuery; -import org.hibernate.criterion.Criterion; -import org.hibernate.criterion.Example.PropertySelector; -import org.hibernate.criterion.MatchMode; -import org.hibernate.criterion.Restrictions; -import org.hibernate.criterion.SimpleExpression; -import org.hibernate.engine.TypedValue; -import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.type.AbstractComponentType; -import org.hibernate.type.Type; -import org.hibernate.util.StringHelper; - -/** - * A copy of Hibernate's Example class, with modifications that allow you to - * include many-to-one and one-to-one associations in Query By Example (QBE) - * queries. - * - * @author original code by Gavin King, modified by jkelly - * @see Example and - * association class - */ -public class AssociationExample implements Criterion { - - /** - * - */ - private static final long serialVersionUID = 3332913458038294975L; - private final Object entity; - private final Set excludedProperties = new HashSet(); - private PropertySelector selector; - private boolean isLikeEnabled; - private boolean isIgnoreCaseEnabled; - private MatchMode matchMode; - private boolean includeAssociations = true; - - /** - * A strategy for choosing property values for inclusion in the query - * criteria - */ - -/** public static interface PropertySelector { - public boolean include(Object propertyValue, String propertyName, - Type type); - }**/ - - private static final PropertySelector NOT_NULL = new NotNullPropertySelector(); - private static final PropertySelector ALL = new AllPropertySelector(); - private static final PropertySelector NOT_NULL_OR_ZERO = new NotNullOrZeroPropertySelector(); - - static final class AllPropertySelector implements PropertySelector { - /** - * - */ - private static final long serialVersionUID = -782949744833744192L; - - public boolean include(Object object, String propertyName, Type type) { - return true; - } - } - - @SuppressWarnings("serial") - static final class NotNullPropertySelector implements PropertySelector { - public boolean include(Object object, String propertyName, Type type) { - return object != null; - } - } - - @SuppressWarnings("serial") - static final class NotNullOrZeroPropertySelector implements - PropertySelector { - public boolean include(Object object, String propertyName, Type type) { - return object != null - && (!(object instanceof Number) || ((Number) object) - .longValue() != 0); - } - } - - /** - * Set the property selector - */ - public AssociationExample setPropertySelector(PropertySelector selector) { - this.selector = selector; - return this; - } - - /** - * Exclude zero-valued properties - */ - public AssociationExample excludeZeroes() { - setPropertySelector(NOT_NULL_OR_ZERO); - return this; - } - - /** - * Don't exclude null or zero-valued properties - */ - public AssociationExample excludeNone() { - setPropertySelector(ALL); - return this; - } - - /** - * Use the "like" operator for all string-valued properties - */ - public AssociationExample enableLike(MatchMode matchMode) { - isLikeEnabled = true; - this.matchMode = matchMode; - return this; - } - - /** - * Use the "like" operator for all string-valued properties - */ - public AssociationExample enableLike() { - return enableLike(MatchMode.EXACT); - } - - /** - * Ignore case for all string-valued properties - */ - public AssociationExample ignoreCase() { - isIgnoreCaseEnabled = true; - return this; - } - - /** - * Exclude a particular named property - */ - public AssociationExample excludeProperty(String name) { - excludedProperties.add(name); - return this; - } - - /** - * Create a new instance, which includes all non-null properties by default - * - * @param entity - * @return a new instance of Example - */ - public static AssociationExample create(Object entity) { - if (entity == null) - throw new NullPointerException("null AssociationExample"); - return new AssociationExample(entity, NOT_NULL); - } - - protected AssociationExample(Object entity, PropertySelector selector) { - this.entity = entity; - this.selector = selector; - } - - public String toString() { - return "example (" + entity + ')'; - } - - private boolean isPropertyIncluded(Object value, String name, Type type) { - return !excludedProperties.contains(name) - && selector.include(value, name, type) - && (!type.isAssociationType() || (type.isAssociationType() - && includeAssociations && !type.isCollectionType())); - } - - public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) - throws HibernateException { - - StringBuffer buf = new StringBuffer().append('('); - EntityPersister meta = criteriaQuery.getFactory().getEntityPersister( - criteriaQuery.getEntityName(criteria)); - String[] propertyNames = meta.getPropertyNames(); - Type[] propertyTypes = meta.getPropertyTypes(); - // TODO: get all properties, not just the fetched ones! - Object[] propertyValues = meta.getPropertyValues(entity, getEntityMode( - criteria, criteriaQuery)); - for (int i = 0; i < propertyNames.length; i++) { - Object propertyValue = propertyValues[i]; - String propertyName = propertyNames[i]; - - boolean isPropertyIncluded = i != meta.getVersionProperty() - && isPropertyIncluded(propertyValue, propertyName, - propertyTypes[i]); - if (isPropertyIncluded) { - if (propertyTypes[i].isComponentType()) { - appendComponentCondition(propertyName, propertyValue, - (AbstractComponentType) propertyTypes[i], criteria, - criteriaQuery, buf); - } else { - appendPropertyCondition(propertyName, propertyValue, - criteria, criteriaQuery, buf); - } - } - } - if (buf.length() == 1) - buf.append("1=1"); // yuck! - return buf.append(')').toString(); - } - - private static final Object[] TYPED_VALUES = new TypedValue[0]; - - public TypedValue[] getTypedValues(Criteria criteria, - CriteriaQuery criteriaQuery) throws HibernateException { - - EntityPersister meta = criteriaQuery.getFactory().getEntityPersister( - criteriaQuery.getEntityName(criteria)); - String[] propertyNames = meta.getPropertyNames(); - Type[] propertyTypes = meta.getPropertyTypes(); - // TODO: get all properties, not just the fetched ones! - Object[] values = meta.getPropertyValues(entity, getEntityMode( - criteria, criteriaQuery)); - List list = new ArrayList(); - for (int i = 0; i < propertyNames.length; i++) { - Object value = values[i]; - Type type = propertyTypes[i]; - String name = propertyNames[i]; - - boolean isPropertyIncluded = i != meta.getVersionProperty() - && isPropertyIncluded(value, name, type); - - if (isPropertyIncluded) { - if (propertyTypes[i].isComponentType()) { - addComponentTypedValues(name, value, - (AbstractComponentType) type, list, criteria, - criteriaQuery); - } else { - addPropertyTypedValue(value, type, list); - } - } - } - return (TypedValue[]) list.toArray(TYPED_VALUES); - } - - private EntityMode getEntityMode(Criteria criteria, - CriteriaQuery criteriaQuery) { - EntityPersister meta = criteriaQuery.getFactory().getEntityPersister( - criteriaQuery.getEntityName(criteria)); - EntityMode result = meta.guessEntityMode(entity); - if (result == null) { - throw new ClassCastException(entity.getClass().getName()); - } - return result; - } - - protected void addPropertyTypedValue(Object value, Type type, List list) { - if (value != null) { - if (value instanceof String) { - String string = (String) value; - if (isIgnoreCaseEnabled) - string = string.toLowerCase(); - if (isLikeEnabled) - string = matchMode.toMatchString(string); - value = string; - } - list.add(new TypedValue(type, value, null)); - } - } - - protected void addComponentTypedValues(String path, Object component, - AbstractComponentType type, List list, Criteria criteria, - CriteriaQuery criteriaQuery) throws HibernateException { - - if (component != null) { - String[] propertyNames = type.getPropertyNames(); - Type[] subtypes = type.getSubtypes(); - Object[] values = type.getPropertyValues(component, getEntityMode( - criteria, criteriaQuery)); - for (int i = 0; i < propertyNames.length; i++) { - Object value = values[i]; - Type subtype = subtypes[i]; - String subpath = StringHelper.qualify(path, propertyNames[i]); - if (isPropertyIncluded(value, subpath, subtype)) { - if (subtype.isComponentType()) { - addComponentTypedValues(subpath, value, - (AbstractComponentType) subtype, list, - criteria, criteriaQuery); - } else { - addPropertyTypedValue(value, subtype, list); - } - } - } - } - } - - protected void appendPropertyCondition(String propertyName, - Object propertyValue, Criteria criteria, CriteriaQuery cq, - StringBuffer buf) throws HibernateException { - Criterion crit; - if (propertyValue != null) { - boolean isString = propertyValue instanceof String; - SimpleExpression se = (isLikeEnabled && isString) ? Restrictions - .like(propertyName, propertyValue) : Restrictions.eq( - propertyName, propertyValue); - crit = (isIgnoreCaseEnabled && isString) ? se.ignoreCase() : se; - } else { - crit = Restrictions.isNull(propertyName); - } - String critCondition = crit.toSqlString(criteria, cq); - if (buf.length() > 1 && critCondition.trim().length() > 0) - buf.append(" and "); - buf.append(critCondition); - } - - protected void appendComponentCondition(String path, Object component, - AbstractComponentType type, Criteria criteria, - CriteriaQuery criteriaQuery, StringBuffer buf) - throws HibernateException { - - if (component != null) { - String[] propertyNames = type.getPropertyNames(); - Object[] values = type.getPropertyValues(component, getEntityMode( - criteria, criteriaQuery)); - Type[] subtypes = type.getSubtypes(); - for (int i = 0; i < propertyNames.length; i++) { - String subpath = StringHelper.qualify(path, propertyNames[i]); - Object value = values[i]; - if (isPropertyIncluded(value, subpath, subtypes[i])) { - Type subtype = subtypes[i]; - if (subtype.isComponentType()) { - appendComponentCondition(subpath, value, - (AbstractComponentType) subtype, criteria, - criteriaQuery, buf); - } else { - appendPropertyCondition(subpath, value, criteria, - criteriaQuery, buf); - } - } - } - } - } - - public boolean isIncludeAssociations() { - return includeAssociations; - } - - public void setIncludeAssociations(boolean includeAssociations) { - this.includeAssociations = includeAssociations; - } -} diff --git a/src/main/java/com/percero/agents/sync/hibernate/BaseDataObjectPropertySelector.java b/src/main/java/com/percero/agents/sync/hibernate/BaseDataObjectPropertySelector.java deleted file mode 100644 index 67a22af..0000000 --- a/src/main/java/com/percero/agents/sync/hibernate/BaseDataObjectPropertySelector.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.percero.agents.sync.hibernate; - -import java.util.Date; -import java.util.List; - -import org.hibernate.criterion.Example.PropertySelector; -import org.hibernate.type.BooleanType; -import org.hibernate.type.IntegerType; -import org.hibernate.type.StringType; -import org.hibernate.type.TimestampType; -import org.hibernate.type.Type; - -import com.percero.framework.vo.IPerceroObject; - -@SuppressWarnings("serial") -public class BaseDataObjectPropertySelector implements PropertySelector { - - public BaseDataObjectPropertySelector(List excludeProps) { - excludeProperties = excludeProps; - } - - public List excludeProperties = null; - - public boolean include(Object propertyValue, String propertyName, Type type) { - if (propertyValue == null) { - return false; - } else if (excludeProperties != null && excludeProperties.contains(propertyName)) { - return false; - } - - if (type instanceof StringType) { - if (((String)propertyValue).length() == 0) { - return false; - } else { - return true; - } - } else if (type.isEntityType()) { - if (propertyValue instanceof IPerceroObject) { - if (((IPerceroObject)propertyValue).getID() != null && !((IPerceroObject)propertyValue).getID().equals("") && !((IPerceroObject)propertyValue).getID().equals("0")) { - return true; - } else { - return false; - } - } else { - return false; - } - } else if (type instanceof IntegerType) { - if (((Integer)propertyValue) != 0) { - return true; - } else { - return false; - } - } else if (type instanceof TimestampType) { - if (((Date)propertyValue).getTime() != 0) { - return true; - } else { - return false; - } - } else if (type instanceof BooleanType) { - return false; - } - return true; - } - -} diff --git a/src/main/java/com/percero/agents/sync/hibernate/ISessionManager.java b/src/main/java/com/percero/agents/sync/hibernate/ISessionManager.java deleted file mode 100644 index 3f39a00..0000000 --- a/src/main/java/com/percero/agents/sync/hibernate/ISessionManager.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.percero.agents.sync.hibernate; - - -public interface ISessionManager { - - public Object createObject(Object theObject, String userId) throws Exception; - public Object putObject(Object theObject, String userId) throws Exception; - public Object deleteObject(Object theObject, String userId) throws Exception; -} \ No newline at end of file diff --git a/src/main/java/com/percero/agents/sync/hibernate/SyncHibernateUtils.java b/src/main/java/com/percero/agents/sync/hibernate/SyncHibernateUtils.java deleted file mode 100644 index 7175938..0000000 --- a/src/main/java/com/percero/agents/sync/hibernate/SyncHibernateUtils.java +++ /dev/null @@ -1,730 +0,0 @@ -package com.percero.agents.sync.hibernate; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -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.TreeSet; - -import javax.persistence.Entity; - -import org.apache.log4j.Logger; -import org.hibernate.ObjectNotFoundException; -import org.hibernate.Query; -import org.hibernate.Session; -import org.hibernate.collection.PersistentBag; -import org.hibernate.collection.PersistentList; -import org.hibernate.collection.PersistentMap; -import org.hibernate.collection.PersistentSet; -import org.hibernate.collection.PersistentSortedSet; -import org.hibernate.proxy.HibernateProxy; -import org.hibernate.proxy.HibernateProxyHelper; -import org.springframework.util.StringUtils; - -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.vo.BaseDataObject; -import com.percero.framework.vo.IPerceroObject; - - -// TODO: Utilize MappedClass.readAccessRightsFieldReferences to optimize read access checking. - -public class SyncHibernateUtils { - - private static final Logger log = Logger.getLogger(SyncHibernateUtils.class); - - public static Object initHibernateProxy(HibernateProxy hp) { - try { - return hp.getHibernateLazyInitializer().getImplementation(); - } catch(ObjectNotFoundException onfe) { - return null; - } catch(Exception e) { - return null; - } - } - - public static Object loadObject(Object object) { - if (object instanceof HibernateProxy) - object = initHibernateProxy((HibernateProxy) object); - - return object; - } - - public static Boolean isProxy(Object object) { - return (object instanceof HibernateProxy); - } - public static Object cleanObject(Object object, Session s) { - return cleanObject(object, s, new HashMap(), null); - } - public static Object cleanObject(Object object, Session s, String userId) { - return cleanObject(object, s, new HashMap(), userId); - } - @SuppressWarnings({"unchecked", "rawtypes"}) - private static Object cleanObject(Object object, Session s, Map inProcessObjects, String userId) { - /** - * Used to indicate that we have already cleaned this object in general, and now only - * fields that have readAccessRights need to be recalculated. - */ - boolean isClean = false; - if (object == null) - return null; - - if (object instanceof List) { - List list = (List) object; - for (int i = 0; i < list.size(); i++) { - Object nextObject = list.get(i); - if (inProcessObjects.containsKey(nextObject)) - nextObject = inProcessObjects.get(nextObject); - list.set(i, cleanObject(nextObject, s, inProcessObjects, userId)); - } - - return list; - } - - if (object instanceof Map) { - Map map = (Map) object; - Map newMap = new HashMap(); - for(Object key : map.keySet()) { - Object nextObject = map.get(key); - if (inProcessObjects.containsKey(nextObject)) - nextObject = inProcessObjects.get(nextObject); - newMap.put(key, cleanObject(nextObject, s, inProcessObjects, userId)); - } - - return newMap; - } - - if (inProcessObjects.containsKey(object)) - return inProcessObjects.get(object); - - Entity entity = object.getClass().getAnnotation(Entity.class); - if (entity == null && !(object instanceof HibernateProxy)) { - inProcessObjects.put(object, object); - return object; - } - // Check to see if this object is clean. - else if (((object instanceof BaseDataObject) && ((BaseDataObject)object).getIsClean())) { - if (!StringUtils.hasText(userId)) { - // If their is a User, need to check to see if any Fields have ReadAccessRights, if not then - // we can just return the object as-is. Otherwise, we need to recalculate just those fields. - inProcessObjects.put(object, object); - return object; - } - else { - isClean = true; - } - } - else if (object instanceof HibernateProxy) - { - object = ((HibernateProxy) object).getHibernateLazyInitializer().getImplementation(); - - // Check to see if this object is in the inProcessObjects. - if (inProcessObjects.containsKey(object)) - return inProcessObjects.get(object); - } - - Class objectClass = HibernateProxyHelper.getClassWithoutInitializingProxy(object); - - Object newObject = null; - try { - newObject = objectClass.newInstance(); - inProcessObjects.put(object, newObject); - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mc = mcm.getMappedClassByClassName(objectClass.getName()); - - for(MappedField theMappedField : mc.toManyFields) { - Object fieldObject = theMappedField.getGetter().invoke(object); - if (fieldObject == null) - theMappedField.getSetter().invoke(newObject, fieldObject); - else if (fieldObject instanceof PersistentList) { - handleCollection(object, newObject, mc, theMappedField, (Collection) fieldObject, new ArrayList(), userId, mcm, s, inProcessObjects, isClean); - //handlePersistentList(object, newObject, mc, theMappedField, (PersistentList) fieldObject, userId, mcm, s, inProcessObjects); - } else if (fieldObject instanceof PersistentBag) { - handleCollection(object, newObject, mc, theMappedField, (Collection) fieldObject, new ArrayList(), userId, mcm, s, inProcessObjects, isClean); - //handlePersistentBag(object, newObject, mc, theMappedField, (PersistentBag) fieldObject, userId, mcm, s, inProcessObjects); - } else if (fieldObject instanceof PersistentSortedSet) { - handleCollection(object, newObject, mc, theMappedField, (Collection) fieldObject, new TreeSet(), userId, mcm, s, inProcessObjects, isClean); - //handlePersistentSortedSet(object, newObject, mc, theMappedField, (PersistentSortedSet) fieldObject, userId, mcm, s, inProcessObjects); - } else if (fieldObject instanceof PersistentSet) { - handleCollection(object, newObject, mc, theMappedField, (Collection) fieldObject, new HashSet(), userId, mcm, s, inProcessObjects, isClean); - } else if (fieldObject instanceof PersistentMap) { - handleMap(object, newObject, mc, theMappedField, (PersistentMap) fieldObject, new HashMap(), userId, mcm, s, inProcessObjects, isClean); - } else if (fieldObject instanceof HibernateProxy) { - handleFieldObject(object, newObject, mc, theMappedField, fieldObject, userId, mcm, s, inProcessObjects, isClean); - /** - if (theMappedField.getUseLazyLoading()) - try { - boolean hasAccess = true; - if (userId != null && userId.length() > 0) { - // Need to check read access. - hasAccess = hasAccess(fieldObject, userId, mcm, s); - } - - if (hasAccess) { - theMappedField.getSetter().invoke(newObject, getShell(fieldObject)); - } - } catch(Exception e) { - e.printStackTrace(); - } - else - theMappedField.getSetter().invoke(newObject, cleanObject(fieldObject, s, inProcessObjects, userId)); - */ - } - else if (fieldObject instanceof List) { - handleCollection(objectClass, newObject, mc, theMappedField, (List) fieldObject, new ArrayList(), userId, mcm, s, inProcessObjects, isClean); - } - } - - for(MappedField theMappedField : mc.toOneFields) { - Object fieldObject = theMappedField.getGetter().invoke(object); - if (fieldObject == null) - theMappedField.getSetter().invoke(newObject, fieldObject); - else if (fieldObject instanceof HibernateProxy) { - handleFieldObject(object, newObject, mc, theMappedField, fieldObject, userId, mcm, s, inProcessObjects, isClean); - /** - boolean hasAccess = true; - if (userId != null && userId.length() > 0) { - // Need to check read access. - hasAccess = hasAccess(fieldObject, userId, mcm, s); - } - - if (hasAccess) { - if (theMappedField.getUseLazyLoading()) - try { - theMappedField.getSetter().invoke(newObject, getShell(fieldObject)); - } catch(Exception e) { - e.printStackTrace(); - } - else - theMappedField.getSetter().invoke(newObject, cleanObject(fieldObject, s, inProcessObjects, userId)); - } - */ - } else if (fieldObject instanceof IPerceroObject) { - handleFieldObject(object, newObject, mc, (MappedFieldPerceroObject) theMappedField, (IPerceroObject) fieldObject, userId, mcm, s, inProcessObjects, isClean); - /** - boolean hasAccess = true; - if (userId != null && userId.length() > 0) { - // Need to check read access. - hasAccess = hasAccess(fieldObject, userId, mcm, s); - } - - if (hasAccess) { - if (s != null) { - theMappedField.getSetter().invoke(newObject, getShell(fieldObject)); - //theMappedField.getSetter().invoke(newObject, s.load(fieldObject.getClass(), ((IPerceroObject) fieldObject).getID())); - } - else - theMappedField.getSetter().invoke(newObject, fieldObject); - } - */ - } - } - - for(MappedField theMappedField : mc.propertyFields) { - Object fieldObject = theMappedField.getGetter().invoke(object); - if (fieldObject == null) - theMappedField.getSetter().invoke(newObject, fieldObject); - else if (fieldObject instanceof HibernateProxy) { - handleFieldObject(object, newObject, mc, theMappedField, fieldObject, userId, mcm, s, inProcessObjects, isClean); - /** - boolean hasAccess = true; - if (userId != null && userId.length() > 0) { - // Need to check read access. - hasAccess = hasAccess(fieldObject, userId, mcm, s); - } - - if (hasAccess) { - if (theMappedField.getUseLazyLoading()) - try { - theMappedField.getSetter().invoke(newObject, getShell(fieldObject)); - } catch(Exception e) { - e.printStackTrace(); - } - else - theMappedField.getSetter().invoke(newObject, cleanObject(fieldObject, s, inProcessObjects, userId)); - } - */ - } else { - handleFieldObject(object, newObject, mc, theMappedField, fieldObject, userId, mcm, s, inProcessObjects, isClean); - /** - if (theMappedField.getUseLazyLoading()) - theMappedField.getSetter().invoke(newObject, fieldObject); - else - theMappedField.getSetter().invoke(newObject, cleanObject(fieldObject, s, inProcessObjects, userId)); - */ - } - } - /** - for(MappedField theMappedField : mc.allFields) { - Object fieldObject = theMappedField.getGetter().invoke(object); - if (fieldObject == null) - theMappedField.getSetter().invoke(newObject, fieldObject); - else if (fieldObject instanceof PersistentList) { - try { - PersistentList pList = (PersistentList) fieldObject; - SessionImplementor session = pList.getSession(); - if (session != null && session.isOpen()) { - List ar = new ArrayList(); - for (Object ob : pList) { - if (theMappedField.getUseLazyLoading()) - ar.add(getShell(ob)); - else - ar.add(cleanObject(ob, s, inProcessObjects)); - } - theMappedField.getSetter().invoke(newObject, ar); - } else { - log.warn("Session is not open. Unable to clean field."); - } - } catch(Exception e) { - e.printStackTrace(); - } - } else if (fieldObject instanceof PersistentBag) { - try { - PersistentBag pBag = (PersistentBag) fieldObject; - SessionImplementor session = (SessionImplementor) s; - if (s == null) - session = pBag.getSession(); - if (session != null && session.isOpen()) { - List ar = new ArrayList(); - for (Object ob : pBag) { - if (theMappedField.getUseLazyLoading()) - ar.add(getShell(ob)); - else - ar.add(cleanObject(ob, s, inProcessObjects)); - } - theMappedField.getSetter().invoke(newObject, ar); - } else { - log.warn("Session is not open. Unable to clean field."); - } - } catch(Exception e) { - e.printStackTrace(); - } - } else if (fieldObject instanceof PersistentSortedSet) { - try { - PersistentSortedSet pSortedSet = (PersistentSortedSet) fieldObject; - SessionImplementor session = pSortedSet.getSession(); - if (session != null && session.isOpen()) { - SortedSet ar = new TreeSet(); - for (Object ob : pSortedSet) { - if (theMappedField.getUseLazyLoading()) - ar.add(getShell(ob)); - else - ar.add(cleanObject(ob, s, inProcessObjects)); - } - theMappedField.getSetter().invoke(newObject, ar); - } else { - log.warn("Session is not open. Unable to clean field."); - } - } catch(Exception e) { - e.printStackTrace(); - } - } else if (fieldObject instanceof PersistentSet) { - try { - PersistentSet pSet = (PersistentSet) fieldObject; - SessionImplementor session = pSet.getSession(); - if (session != null && session.isOpen()) { - Set ar = new HashSet(); - for (Object ob : pSet) { - if (theMappedField.getUseLazyLoading()) - ar.add(getShell(ob)); - else - ar.add(cleanObject(ob, s, inProcessObjects)); - } - theMappedField.getSetter().invoke(newObject, ar); - } else { - log.warn("Session is not open. Unable to clean field."); - } - } catch(Exception e) { - e.printStackTrace(); - } - } else if (fieldObject instanceof PersistentMap) { - try { - PersistentMap pMap = (PersistentMap) fieldObject; - SessionImplementor session = pMap.getSession(); - if (session != null && session.isOpen()) { - Map hm = new HashMap(); - for (Object nextKey : pMap.keySet()) { - try { - if (theMappedField.getUseLazyLoading()) - hm.put(nextKey, getShell(pMap.get(nextKey))); - else - hm.put(nextKey, cleanObject(pMap.get(nextKey), s, inProcessObjects)); - } catch(Exception e) { - e.printStackTrace(); - } - } - theMappedField.getSetter().invoke(newObject, hm); - } else { - log.warn("Session is not open. Unable to clean field."); - } - } catch(Exception e) { - e.printStackTrace(); - } - } else if (fieldObject instanceof HibernateProxy) { - if (theMappedField.getUseLazyLoading()) - try { - theMappedField.getSetter().invoke(newObject, getShell(fieldObject)); - } catch(Exception e) { - e.printStackTrace(); - } - else - theMappedField.getSetter().invoke(newObject, cleanObject(fieldObject, s, inProcessObjects)); - } else if (fieldObject instanceof IPerceroObject) { - if (s != null) - theMappedField.getSetter().invoke(newObject, s.load(fieldObject.getClass(), ((IPerceroObject) fieldObject).getID())); - else - theMappedField.getSetter().invoke(newObject, fieldObject); - } else { - if (theMappedField.getUseLazyLoading()) - theMappedField.getSetter().invoke(newObject, fieldObject); - else - theMappedField.getSetter().invoke(newObject, cleanObject(fieldObject, s, inProcessObjects)); - } - } - */ - if (newObject instanceof BaseDataObject) { - ((BaseDataObject) newObject).setIsClean(true); - } - } catch(Exception e) { - e.printStackTrace(); - } - - return newObject; - } - - private static void handleFieldObject(Object theObject, Object newObject, MappedClass mc, MappedField theMappedField, Object theFieldObject, String userId, IMappedClassManager mcm, Session s, Map inProcessObjects, boolean isClean) { - try { - if (theFieldObject == null) { - theMappedField.getSetter().invoke(newObject, theFieldObject); - return; - } - - boolean isUser = StringUtils.hasText(userId); - if (isClean) { - // Object is clean. - if (!theMappedField.getHasReadAccessRights()) { - // Since the MappedField has no ReadAccessRights, we can do a straight copy here. - theMappedField.getSetter().invoke(newObject, theFieldObject); - return; - } - else if (!isUser) { - // Since there is no User, we have no need to check AccessRights. - theMappedField.getSetter().invoke(newObject, theFieldObject); - return; - } - } - - if (theMappedField.getReadQuery() != null && StringUtils.hasText(theMappedField.getReadQuery().getQuery())) { - if (hasFieldAccess(theObject, userId, theMappedField, s)) { - // Since the user has access to this entire field, no need to check each individual object. - theMappedField.getSetter().invoke(newObject, theFieldObject); - return; - } - else { - // Since the user does NOT have access to this entire field, we return an empty collection. - Object[] nullObject = new Object[1]; - nullObject[0] = null; - theMappedField.getSetter().invoke(newObject, nullObject); - return; - } - } - - if (theFieldObject instanceof IPerceroObject) { - if (s != null && s.isOpen()) { - if (!isUser || hasAccess(theFieldObject, userId, mcm, s)) { - if (theMappedField.getUseLazyLoading()) - theMappedField.getSetter().invoke(newObject, getShell(theFieldObject)); - else - theMappedField.getSetter().invoke(newObject, cleanObject(theFieldObject, s, inProcessObjects, userId)); - } - } else { - Object[] nullObject = new Object[1]; - nullObject[0] = null; - theMappedField.getSetter().invoke(newObject, nullObject); - log.warn("Session is not open. Unable to clean field."); - } - } - else { - // Must be some primitive type. - if (theMappedField.getUseLazyLoading()) - theMappedField.getSetter().invoke(newObject, theFieldObject); - else - theMappedField.getSetter().invoke(newObject, cleanObject(theFieldObject, s, inProcessObjects, userId)); - } - } catch(Exception e) { - log.error("Unable to clean field " + mc.className + ":" + theMappedField.getField().getName(), e); - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static void handleCollection(Object theObject, Object newObject, MappedClass mc, MappedField theMappedField, Collection theCollection, Collection newCollection, String userId, IMappedClassManager mcm, Session s, Map inProcessObjects, boolean isClean) { - try { - boolean isUser = StringUtils.hasText(userId); - if (isClean) { - // Object is clean. - if (!theMappedField.getHasReadAccessRights()) { - // Since the MappedField has no ReadAccessRights, we can do a straight copy here. - newCollection.addAll(theCollection); - theMappedField.getSetter().invoke(newObject, newCollection); - return; - } - else if (!isUser) { - // Since there is no User, we have no need to check AccessRights. - newCollection.addAll(theCollection); - theMappedField.getSetter().invoke(newObject, newCollection); - return; - } - } - - if (theMappedField.getReadQuery() != null && StringUtils.hasText(theMappedField.getReadQuery().getQuery())) { - if (hasFieldAccess(theObject, userId, theMappedField, s)) { - // Since the user has access to this entire field, no need to check each individual object. - // However, since the object isn't clean, need to get clean version of each object. - for (Object nextCollectionObject : theCollection) { - // If there is no user, or the user has access... - if (theMappedField.getUseLazyLoading()) - newCollection.add(getShell(nextCollectionObject)); - else - newCollection.add(cleanObject(nextCollectionObject, s, inProcessObjects, userId)); - } - theMappedField.getSetter().invoke(newObject, newCollection); - return; - } - else { - // Since the user does NOT have access to this entire field, we return an empty collection. - theMappedField.getSetter().invoke(newObject, newCollection); - return; - } - } - - if (s != null && s.isOpen()) { - for (Object nextCollectionObject : theCollection) { - // If there is no user, or the user has access... - if (!isUser || hasAccess(nextCollectionObject, userId, mcm, s)) { - if (theMappedField.getUseLazyLoading()) - newCollection.add(getShell(nextCollectionObject)); - else - newCollection.add(cleanObject(nextCollectionObject, s, inProcessObjects, userId)); - } - } - } else { - log.warn("Session is not open. Unable to clean field."); - } - theMappedField.getSetter().invoke(newObject, newCollection); - } catch(Exception e) { - log.error("Unable to clean field " + mc.className + ":" + theMappedField.getField().getName(), e); - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static void handleMap(Object object, Object newObject, MappedClass mc, MappedField theMappedField, Map pMap, Map newMap, String userId, IMappedClassManager mcm, Session s, Map inProcessObjects, boolean isClean) { - try { - boolean isUser = StringUtils.hasText(userId); - if (isClean) { - // Object is clean. - if (!theMappedField.getHasReadAccessRights()) { - // Since the MappedField has no ReadAccessRights, we can do a straight copy here. - theMappedField.getSetter().invoke(newObject, pMap); - return; - } - else if (!isUser) { - // Since there is no User, we have no need to check AccessRights. - theMappedField.getSetter().invoke(newObject, pMap); - return; - } - } - - if (theMappedField.getReadQuery() != null && StringUtils.hasText(theMappedField.getReadQuery().getQuery())) { - if (hasFieldAccess(object, userId, theMappedField, s)) { - // Since the user has access to this entire field, no need to check each individual object. - theMappedField.getSetter().invoke(newObject, pMap); - return; - } - else { - // Since the user does NOT have access to this entire field, we return an empty collection. - theMappedField.getSetter().invoke(newObject, newMap); - return; - } - } - - if (s != null && s.isOpen()) { - Iterator itrPMapEntries = pMap.entrySet().iterator(); - while (itrPMapEntries.hasNext()) { - Map.Entry nextEntry = itrPMapEntries.next(); - Object ob = nextEntry.getValue(); - if (!isUser || hasAccess(ob, userId, mcm, s)) { - Object nextKey = nextEntry.getKey(); - try { - if (theMappedField.getUseLazyLoading()) - newMap.put(nextKey, getShell(ob)); - else - newMap.put(nextKey, cleanObject(ob, s, inProcessObjects, userId)); - } catch(Exception e) { - e.printStackTrace(); - } - } - } -// for (Object nextKey : pMap.keySet()) { -// Object ob = pMap.get(nextKey); -// if (!isUser || hasAccess(ob, userId, mcm, s)) { -// try { -// if (theMappedField.getUseLazyLoading()) -// newMap.put(nextKey, getShell(ob)); -// else -// newMap.put(nextKey, cleanObject(ob, s, inProcessObjects, userId)); -// } catch(Exception e) { -// e.printStackTrace(); -// } -// } -// } - } else { - log.warn("Session is not open. Unable to clean field."); - } - theMappedField.getSetter().invoke(newObject, newMap); - } catch(Exception e) { - log.error("Unable to clean field " + mc.className + ":" + theMappedField.getField().getName(), e); - } - } - - - - private static boolean hasAccess(Object ob, String userId, IMappedClassManager mcm, Session s) { - boolean hasAccess = true; - if (StringUtils.hasText(userId)) { - try { - ob = getShell(ob); - MappedClass mappedClass = mcm.getMappedClassByClassName(ob.getClass().getCanonicalName()); - boolean isValidReadQuery = false; - if (mappedClass != null) { - if (mappedClass.getReadQuery() != null && StringUtils.hasText(mappedClass.getReadQuery().getQuery())) { - isValidReadQuery = true; - } - } - - if (isValidReadQuery) { - // There is a ReadQuery, so process that. - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter.getQueryString(), ob, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - } catch (Exception e) { - hasAccess = false; - } - } - - return hasAccess; - } - - - private static boolean hasFieldAccess(Object ob, String userId, MappedField mappedField, Session s) { - boolean hasAccess = true; - if (StringUtils.hasText(userId)) { - try { - boolean isValidReadQuery = false; - if (mappedField.getReadQuery() != null && StringUtils.hasText(mappedField.getReadQuery().getQuery())) - isValidReadQuery = true; - - if (isValidReadQuery) { - ob = getShell(ob); - // There is a ReadQuery, so process that. - Query readFilter = s.createQuery(mappedField.getReadQuery().getQuery()); - mappedField.getReadQuery().setQueryParameters(readFilter.getQueryString(), ob, userId); - Number readFilterResult = (Number) readFilter.uniqueResult(); - if (readFilterResult == null || readFilterResult.intValue() <= 0) - hasAccess = false; - } - } catch (Exception e) { - hasAccess = false; - } - } - - return hasAccess; - } - - public static Object getShell(Object object) { - if (object instanceof HibernateProxy) { - object = initHibernateProxy((HibernateProxy) object); - } - - return object; - } - - @SuppressWarnings("rawtypes") - public static List getClassFields(Class theClass) { - List fieldList = new ArrayList(); - Field[] theFields = theClass.getDeclaredFields(); - - for(Field nextField : theFields) { - boolean isStatic = Modifier.STATIC == (nextField.getModifiers() & Modifier.STATIC); - if (!isStatic) - fieldList.add(nextField); - } - - if (theClass.getSuperclass() != null) - fieldList.addAll(getClassFields(theClass.getSuperclass())); - - return fieldList; - } - - @SuppressWarnings("rawtypes") - public static Method getFieldGetters(Class theClass, Field theField) { - Method theMethod = null; - Method[] theMethods = theClass.getMethods(); - String theModifiedFieldName = theField.getName(); - if (theModifiedFieldName.indexOf("_") == 0) - theModifiedFieldName = theModifiedFieldName.substring(1); - - for(Method nextMethod : theMethods) { - if (nextMethod.getName().equalsIgnoreCase("get" + theModifiedFieldName)) { - theMethod = nextMethod; - break; - } - } - - return theMethod; - } - - @SuppressWarnings("rawtypes") - public static Method getFieldSetters(Class theClass, Field theField) { - Method theMethod = null; - Method[] theMethods = theClass.getMethods(); - String theModifiedFieldName = theField.getName(); - if (theModifiedFieldName.indexOf("_") == 0) - theModifiedFieldName = theModifiedFieldName.substring(1); - - for(Method nextMethod : theMethods) { - if (nextMethod.getName().equalsIgnoreCase("set" + theModifiedFieldName)) { - theMethod = nextMethod; - break; - } - } - - return theMethod; - } - - @SuppressWarnings("rawtypes") - public static Object getUniqueResult(Object anObject) { - if (anObject instanceof List) { - List listObject = (List) anObject; - if (listObject.size() >= 1) - return listObject.get(0); - else - return null; - - } else { - return anObject; - } - } - -} \ No newline at end of file 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 4e0192a..97fc5cc 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java @@ -1,5 +1,7 @@ package com.percero.agents.sync.jobs; +import org.springframework.util.StringUtils; + import com.percero.datasource.BaseConnectionFactory; /** @@ -32,6 +34,14 @@ public void setStoredProcedureDefinition(String storedProcedureDefinition) { this.storedProcedureDefinition = storedProcedureDefinition; } + private String rowIdColumnName = "row_id"; + public String getRowIdColumnName() { + return rowIdColumnName; + } + public void setRowIdColumnName(String rowIdColumnName) { + this.rowIdColumnName = rowIdColumnName; + } + private String lockIdColumnName = "lock_id"; public String getLockIdColumnName() { return lockIdColumnName; @@ -56,11 +66,14 @@ public void setTimestampColumnName(String timestampColumnName) { this.timestampColumnName = timestampColumnName; } - private String updateStatementSql = "update :tableName set " + getLockIdColumnName() + "=:lockId, " + getLockDateColumnName() + "=NOW() " + - "where " + getLockIdColumnName() + " is null or " + - getLockDateColumnName() + " < ':expireThreshold' " + - "order by " + getTimestampColumnName() + " limit :limit"; + private String updateStatementSql = null; public String getUpdateStatementSql() { + if (!StringUtils.hasText(updateStatementSql)) { + updateStatementSql = "update :tableName set " + getLockIdColumnName() + "=:lockId, " + getLockDateColumnName() + "=NOW() " + + "where " + getLockIdColumnName() + " is null or " + + getLockDateColumnName() + " < ':expireThreshold' " + + "order by " + getTimestampColumnName() + " limit :limit"; + } return updateStatementSql; } public void setUpdateStatementSql(String updateStatementSql) { 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 b88274b..7647b5c 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTablePoller.java @@ -2,11 +2,10 @@ import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; -import javax.annotation.PostConstruct; - import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -54,28 +53,33 @@ public class UpdateTablePoller { @Autowired @Qualifier("executorWithCallerRunsPolicy") TaskExecutor taskExecutor; + + UpdateTableProcessReporter reporter = null; Map> runningProcessors = java.util.Collections.synchronizedMap(new HashMap>()); public boolean enabled = true; - @PostConstruct - public void init(){ - // Get the reporter going - UpdateTableProcessReporter.getInstance(); - } - /** * Run every minute */ @Scheduled(cron="0/5 * * * * *") // Every 5 seconds public void pollUpdateTables() { - logger.debug("*** UpdateTablePoller running..."); - for (UpdateTableConnectionFactory updateTableConnectionFactory : updateTableRegistry.getConnectionFactories()) { - for (String tableName : updateTableConnectionFactory.getTableNames()) { - doProcessingForTable(updateTableConnectionFactory, tableName); - } - } + List connectionFactories = updateTableRegistry.getConnectionFactories(); + + // Only attempt to process Update Tables if they are configured. + if (connectionFactories != null && !connectionFactories.isEmpty()) { + if (reporter == null) { + // Get the reporter going + reporter = UpdateTableProcessReporter.getInstance(); + } + logger.debug("*** UpdateTablePoller running..."); + for (UpdateTableConnectionFactory updateTableConnectionFactory : connectionFactories) { + for (String tableName : updateTableConnectionFactory.getTableNames()) { + doProcessingForTable(updateTableConnectionFactory, tableName); + } + } + } } @SuppressWarnings("unchecked") 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 52111a0..bcfe405 100644 --- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java +++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableProcessor.java @@ -34,6 +34,7 @@ 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.services.IPushSyncHelper; import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.ClassIDPair; import com.percero.framework.bl.IManifest; @@ -54,6 +55,7 @@ public class UpdateTableProcessor implements Runnable{ protected UpdateTableConnectionFactory connectionFactory; protected PostDeleteHelper postDeleteHelper; protected PostPutHelper postPutHelper; + protected IPushSyncHelper pushSyncHelper; protected IManifest manifest; protected CacheManager cacheManager; protected DataProviderManager dataProviderManager; @@ -133,7 +135,7 @@ public void run(){ result.addResult(row.getType().toString()); successfulRows.add(row); } catch (Exception e) { - logger.warn("Failed to process update: " + e.getMessage(), e); + logger.error("Failed to process update: " + e.getMessage(), e); result.addResult(row.getType().toString(), false, e.getMessage()); releaseRowLock(row); } @@ -150,8 +152,8 @@ public void run(){ } if (!result.isSuccess()) { - logger.warn("Update table processor (" + tableName + ") failed. Details:"); - logger.warn(result); + logger.debug("Update table processor (" + tableName + ") failed. Details:"); + logger.debug(result); } }finally{ try { @@ -207,7 +209,7 @@ protected void processUpdateSingle(UpdateTableRow row) throws Exception{ List classes = getClassesForTableName(row.getTableName()); if (classes == null || classes.isEmpty()) { - logger.warn("No Classes defined for UpdateTable table " + row.getTableName()); + logger.debug("No Classes defined for UpdateTable table " + row.getTableName()); } else { logger.debug("Processing " + classes.size() + " class(es) for UpdateTable UPDATE, table " + row.getTableName()); @@ -237,7 +239,7 @@ protected void processUpdateTable(UpdateTableRow row) throws Exception{ List classes = getClassesForTableName(row.getTableName()); if (classes == null || classes.isEmpty()) { - logger.warn("No Classes defined for UpdateTable table " + row.getTableName()); + logger.debug("No Classes defined for UpdateTable table " + row.getTableName()); } else { logger.debug("Processing " + classes.size() + " class(es) for UpdateTable UPDATE, table " + row.getTableName()); @@ -346,7 +348,7 @@ protected void handleUpdateClassIdPair(IDataProvider dataProvider, ClassIDPair p fieldNames[i] = nextChangedField.getField().getName(); i++; } - postPutHelper.enqueueCheckChangeWatcher(thePair, fieldNames, null, oldValue); + pushSyncHelper.enqueueCheckChangeWatcher(thePair, fieldNames, null, oldValue); } } } @@ -373,7 +375,7 @@ protected void processInsertSingle(UpdateTableRow row) throws Exception{ List classes = getClassesForTableName(row.getTableName()); if (classes == null || classes.isEmpty()) { - logger.warn("No Classes defined for UpdateTable table " + row.getTableName()); + logger.debug("No Classes defined for UpdateTable table " + row.getTableName()); } else { logger.debug("Processing " + classes.size() + " class(es) for UpdateTable INSERT, table " + row.getTableName()); @@ -399,7 +401,7 @@ protected void processInsertTable(UpdateTableRow row) throws Exception { List classes = getClassesForTableName(row.getTableName()); if (classes == null || classes.isEmpty()) { - logger.warn("No Classes defined for UpdateTable table " + row.getTableName()); + logger.debug("No Classes defined for UpdateTable table " + row.getTableName()); } else { logger.debug("Processing " + classes.size() + " class(es) for UpdateTable INSERT, table " + row.getTableName()); @@ -432,7 +434,7 @@ protected void processDeleteSingle(UpdateTableRow row) throws Exception{ List classes = getClassesForTableName(row.getTableName()); if (classes == null || classes.isEmpty()) { - logger.warn("No Classes defined for UpdateTable table " + row.getTableName()); + logger.debug("No Classes defined for UpdateTable table " + row.getTableName()); } else { logger.debug("Processing " + classes.size() + " class(es) for UpdateTable DELETE, table " + row.getTableName()); @@ -463,7 +465,7 @@ protected void processDeleteTable(UpdateTableRow row) throws Exception{ List classes = getClassesForTableName(row.getTableName()); if (classes == null || classes.isEmpty()) { - logger.warn("No Classes defined for UpdateTable table " + row.getTableName()); + logger.debug("No Classes defined for UpdateTable table " + row.getTableName()); } else { logger.debug("Processing " + classes.size() + " class(es) for UpdateTable DELETE, table " + row.getTableName()); @@ -522,7 +524,8 @@ protected void handleDeletedObject(IPerceroObject cachedObject, Class clazz, Str cacheManager.handleDeletedObject(cachedObject, className, isShellObject); - postDeleteHelper.postDeleteObject(new ClassIDPair(id, className), null, null, true); +// postDeleteHelper.postDeleteObject(new ClassIDPair(id, className), null, null, true); + postDeleteHelper.postDeleteObject(cachedObject, null, null, true); } @SuppressWarnings("rawtypes") @@ -564,6 +567,7 @@ protected void updateReferences(String className){ // Find all of this type and push down an update to all Set ids = accessManager.getClassAccessJournalIDs(mappedField.getMappedClass().className); + logger.debug("updateReferences - ids IS NULL : " + (ids == null) ); 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; @@ -572,6 +576,7 @@ protected void updateReferences(String className){ while (total < 0 || pageNumber * pageSize <= total) { PerceroList objectsToUpdate = mappedField.getMappedClass().getDataProvider().getAllByName(mappedField.getMappedClass().className, pageNumber, pageSize, true, null); + logger.debug("updateReferences - objectsToUpdate IS NULL : " + (objectsToUpdate == null) ); pageNumber++; total = objectsToUpdate.getTotalLength(); if (total <= 0) { @@ -581,13 +586,16 @@ protected void updateReferences(String className){ Iterator itrObjectsToUpdate = objectsToUpdate.iterator(); while (itrObjectsToUpdate.hasNext()) { IDataProvider dataProvider = dataProviderManager.getDefaultDataProvider(); + logger.debug("updateReferences - dataProvider IS NULL : " + (dataProvider == null) ); // We assume this is from the cache because some client has requested all of this class // and since we turned off cache expiration it must be in there. BaseDataObject nextObjectToUpdate = (BaseDataObject) itrObjectsToUpdate.next(); + logger.debug("updateReferences - BaseDataObject IS NULL : " + (nextObjectToUpdate == null) ); ClassIDPair pair = BaseDataObject.toClassIdPair(nextObjectToUpdate); + logger.debug("updateReferences - BaseDataObject pair IS NULL : " + (pair == null) ); // This call ignores the cache BaseDataObject nextObjectToUpdateFromDB = (BaseDataObject) dataProvider.findById(pair, null, true); - + logger.debug("updateReferences - nextObjectToUpdateFromDB IS NULL : " + (nextObjectToUpdateFromDB == null) ); Map> changedFields = dataProvider .getChangedMappedFields(nextObjectToUpdateFromDB, nextObjectToUpdate, nextObjectToUpdate != null); @@ -603,14 +611,17 @@ protected void updateReferences(String className){ String nextIdToUpdate = itrIdsToUpdate.next(); ClassIDPair pair = new ClassIDPair(nextIdToUpdate, mappedField.getMappedClass().className); - IDataProvider dataProvider = dataProviderManager.getDefaultDataProvider(); + logger.debug("updateReferences - ELSE pair IS NULL : " + (pair == null) ); + IDataProvider dataProvider = dataProviderManager.getDefaultDataProvider(); + logger.debug("updateReferences - ELSE dataProvider IS NULL : " + (dataProvider == null) ); // First call assumes we are getting it from the cache... because we can assume that // All objects that we care about are all cached (since we turned off cache expiration). BaseDataObject cachedObject = (BaseDataObject) dataProvider.findById(pair, null); + logger.debug("updateReferences - ELSE cachedObject IS NULL : " + (cachedObject == null) ); // This call ignores the cache BaseDataObject objectFromDB = (BaseDataObject) dataProvider.findById(pair, null, true); - + logger.debug("updateReferences - ELSE BaseDataObject objectFromDB IS NULL : " + (objectFromDB == null) ); Map> changedFields = dataProvider .getChangedMappedFields(objectFromDB, cachedObject, cachedObject != null); // Only push if different @@ -715,7 +726,7 @@ private List getUpdateSelectRow(int lockId, DateTime expireThres } if(count != numUpdated) - logger.warn("Locked a "+numUpdated+" rows but found "+count); + logger.debug("Locked a "+numUpdated+" rows but found "+count); } } } @@ -741,7 +752,7 @@ private List getStoredProcRow(int lockId, DateTime expireThresho updateNum = cstmt.getInt(4); } catch(SQLException e){ // return null; - logger.warn(e.getMessage(), e); + logger.error(e.getMessage(), e); // If the stored proc doesn't exist, let's try and create it. if (StringUtils.hasText(connectionFactory.getStoredProcedureDefinition()) && @@ -754,11 +765,11 @@ private List getStoredProcRow(int lockId, DateTime expireThresho System.out.println(createResult); } catch(SQLSyntaxErrorException ssee) { - logger.warn("Unable to create UpdateTable stored procedure: " + ssee.getMessage()); + logger.error("Unable to create UpdateTable stored procedure: " + ssee.getMessage()); throw ssee; } catch(Exception e1) { - logger.warn("Unable to create UpdateTable stored procedure: " + e1.getMessage()); + logger.error("Unable to create UpdateTable stored procedure: " + e1.getMessage()); throw e1; } } @@ -779,7 +790,7 @@ private List getStoredProcRow(int lockId, DateTime expireThresho } if(count != updateNum) - logger.warn("Locked a "+updateNum+" rows but found "+count); + logger.error("Locked a "+updateNum+" rows but found "+count); } } @@ -800,10 +811,11 @@ protected void deleteRows(List rows){ int numUpdated = statement.executeUpdate(sql); if(numUpdated != rows.size()){ - logger.warn("Expected to delete "+rows.size()+", instead "+numUpdated); + //As discussed with Richard, commenting the log +// logger.warn("Expected to delete "+rows.size()+", instead "+numUpdated); } }catch(SQLException e){ - logger.warn(e.getMessage(), e); + logger.error(e.getMessage(), e); } } @@ -817,10 +829,11 @@ protected void releaseRowLock(UpdateTableRow row){ int numUpdated = statement.executeUpdate(sql); if(numUpdated != 1){ - logger.warn("Expected to update 1, instead "+numUpdated); + //As discussed with Richard, commenting the log +// logger.warn("Expected to update 1, instead "+numUpdated); } }catch(SQLException e){ - logger.warn(e.getMessage(), e); + logger.error(e.getMessage(), e); } } @@ -857,13 +870,13 @@ protected UpdateTableRow fromResultSet(ResultSet resultSet) throws SQLException{ UpdateTableRow row = new UpdateTableRow(); row.ID = resultSet.getInt("ID"); row.tableName = resultSet.getString("tableName"); - row.rowId = resultSet.getString("row_id"); + row.rowId = resultSet.getString(connectionFactory.getRowIdColumnName()); row.lockId = resultSet.getInt(connectionFactory.getLockIdColumnName()); row.lockDate = resultSet.getDate(connectionFactory.getLockDateColumnName()); try { row.type = UpdateTableRowType.valueOf(resultSet.getString("type")); } catch(IllegalArgumentException iae) { - logger.warn("Invalid UpdateTableRow TYPE, ignoring"); + logger.error("Invalid UpdateTableRow TYPE, ignoring"); row.type = UpdateTableRowType.NONE; } row.timestamp = resultSet.getDate(connectionFactory.getTimestampColumnName()); diff --git a/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java b/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java deleted file mode 100644 index 90e94cd..0000000 --- a/src/main/java/com/percero/agents/sync/metadata/JpqlQuery.java +++ /dev/null @@ -1,103 +0,0 @@ -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:"); - if (index >= 0) - value = value.substring(index + 5); - super.setQuery(value); - } - - 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; - } - - 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 d3657ba..e21b4d0 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedClass.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedClass.java @@ -1,5 +1,6 @@ package com.percero.agents.sync.metadata; +import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; @@ -35,7 +36,6 @@ import com.percero.agents.sync.annotations.PerceroNamedNativeQueries; import com.percero.agents.sync.annotations.PerceroNamedNativeQuery; -import com.percero.agents.sync.hibernate.SyncHibernateUtils; import com.percero.agents.sync.metadata.annotations.AccessRight; import com.percero.agents.sync.metadata.annotations.AccessRights; import com.percero.agents.sync.metadata.annotations.DataProvider; @@ -56,6 +56,7 @@ import com.percero.framework.metadata.IMappedClass; import com.percero.framework.metadata.IMappedQuery; import com.percero.framework.vo.IPerceroObject; +import com.percero.util.MappedClassUtils; @SuppressWarnings("unchecked") public class MappedClass implements IMappedClass { @@ -228,9 +229,9 @@ public Set getTargetMappedFields() { .synchronizedSet(new HashSet()); public Set externalizableFields = Collections .synchronizedSet(new TreeSet(fieldComparator)); - public Map cascadeRemoveFieldReferences = Collections + private Map cascadeRemoveFieldReferences = Collections .synchronizedMap(new HashMap()); - public Map nulledOnRemoveFieldReferences = Collections + private Map nulledOnRemoveFieldReferences = Collections .synchronizedMap(new HashMap()); @SuppressWarnings("rawtypes") public Map entityImplementations = Collections @@ -415,40 +416,68 @@ protected EntityImplementation processEntityInterface( entityImplementations.put(entityInterface.interfaceClass(), entityImpl); return entityImpl; } - + @SuppressWarnings("rawtypes") + protected MappedField handleCreateMappedFieldFromClass(Class fieldClass) { + MappedField newMappedField = null; + if (fieldClass == int.class) + newMappedField = new MappedFieldInt(); + else if (fieldClass == Integer.class) + newMappedField = new MappedFieldInteger(); + else if (fieldClass == float.class) + newMappedField = new MappedFieldFloat(); + else if (fieldClass == Float.class) + newMappedField = new MappedFieldFloat(); + else if (fieldClass == double.class) + newMappedField = new MappedFieldDouble(); + else if (fieldClass == Double.class) + newMappedField = new MappedFieldDouble(); + else if (fieldClass == boolean.class) + newMappedField = new MappedFieldBool(); + else if (fieldClass == Boolean.class) + newMappedField = new MappedFieldBoolean(); + else if (fieldClass == String.class) + newMappedField = new MappedFieldString(); + else if (fieldClass == Date.class) + newMappedField = new MappedFieldDate(); + /** + * else if (nextFieldClass == Map.class) nextMappedField = new + * MappedFieldMap(); else if (nextFieldClass == List.class) + * nextMappedField = new MappedFieldList(); + **/ + else if (implementsInterface(fieldClass, IPerceroObject.class)) { + newMappedField = new MappedFieldPerceroObject(); + externalizablePerceroObjectFields.add((MappedFieldPerceroObject) newMappedField); + } + else if (implementsInterface(fieldClass, Map.class)) + newMappedField = new MappedFieldMap(); + else if (implementsInterface(fieldClass, List.class)) + newMappedField = new MappedFieldList(); + + else + newMappedField = new MappedField(); + + return newMappedField; + } + public void initializeFields() { if (fieldsInitialized) { return; } try { - Class clazz = MappedClass.forName(className); + if (clazz == null) { + clazz = MappedClass.forName(className); + } - List fields = SyncHibernateUtils.getClassFields(clazz); + List fields = MappedClassUtils.getClassFields(clazz); for (Field nextField : fields) { - // Ignore this field if marked as Transient. - Transient transientAnno = (Transient) nextField - .getAnnotation(Transient.class); - if (transientAnno != null) - continue; - - Externalize externalize = (Externalize) nextField - .getAnnotation(Externalize.class); - if (externalize == null) { - // Only process Externalizeable fields. - continue; - } - // Check to see if this Field has already been processed. - Iterator itrExternalizeFields = externalizableFields - .iterator(); + Iterator itrExternalizeFields = externalizableFields.iterator(); Boolean fieldAlreadyMapped = false; while (itrExternalizeFields.hasNext()) { - MappedField nextExistingMappedField = itrExternalizeFields - .next(); - if (nextExistingMappedField.getField().getName() - .equals(nextField.getName())) { + MappedField nextExistingMappedField = itrExternalizeFields.next(); + if (nextExistingMappedField.getField().getName().equals(nextField.getName())) { // This field has already been mapped. fieldAlreadyMapped = true; break; @@ -459,57 +488,26 @@ public void initializeFields() { continue; } - Method theGetter = SyncHibernateUtils.getFieldGetters(clazz, - nextField); - transientAnno = (Transient) theGetter - .getAnnotation(Transient.class); - if (transientAnno != null) + Method theGetter = MappedClassUtils.getFieldGetters(clazz, nextField); + + // Ignore this field if marked as Transient. + if (hasAnnotation(nextField, theGetter, Transient.class)) continue; - Method theSetter = SyncHibernateUtils.getFieldSetters(clazz, - nextField); - - MappedField nextMappedField = null; - Class nextFieldClass = nextField.getType(); - if (nextFieldClass == int.class) - nextMappedField = new MappedFieldInt(); - else if (nextFieldClass == Integer.class) - nextMappedField = new MappedFieldInteger(); - else if (nextFieldClass == float.class) - nextMappedField = new MappedFieldFloat(); - else if (nextFieldClass == Float.class) - nextMappedField = new MappedFieldFloat(); - else if (nextFieldClass == double.class) - nextMappedField = new MappedFieldDouble(); - else if (nextFieldClass == Double.class) - nextMappedField = new MappedFieldDouble(); - else if (nextFieldClass == boolean.class) - nextMappedField = new MappedFieldBool(); - else if (nextFieldClass == Boolean.class) - nextMappedField = new MappedFieldBoolean(); - else if (nextFieldClass == String.class) - nextMappedField = new MappedFieldString(); - else if (nextFieldClass == Date.class) - nextMappedField = new MappedFieldDate(); - /** - * else if (nextFieldClass == Map.class) nextMappedField = new - * MappedFieldMap(); else if (nextFieldClass == List.class) - * nextMappedField = new MappedFieldList(); - **/ - else if (implementsInterface(nextFieldClass, - IPerceroObject.class)) - nextMappedField = new MappedFieldPerceroObject(); - else if (implementsInterface(nextFieldClass, Map.class)) - nextMappedField = new MappedFieldMap(); - else if (implementsInterface(nextFieldClass, List.class)) - nextMappedField = new MappedFieldList(); - - else - nextMappedField = new MappedField(); + Externalize externalize = retrieveAnnotation(nextField, theGetter, Externalize.class); + if (externalize == null) { + // Only process Externalizeable fields. + continue; + } + + Method theSetter = MappedClassUtils.getFieldSetters(clazz, nextField); + + MappedField nextMappedField = handleCreateMappedFieldFromClass(nextField.getType()); nextMappedField.setMappedClass(this); nextMappedField.setField(nextField); nextMappedField.setGetter(theGetter); nextMappedField.setSetter(theSetter); + externalizableFields.add(nextMappedField); nextMappedField.setUseLazyLoading(externalize.useLazyLoading()); if (!nextMappedField.getUseLazyLoading()) @@ -517,53 +515,14 @@ else if (implementsInterface(nextFieldClass, List.class)) if (!externalize.useLazyLoading()) nonLazyLoadingFields.add(nextMappedField); - externalizableFields.add(nextMappedField); - if (nextMappedField instanceof MappedFieldPerceroObject) - externalizablePerceroObjectFields - .add((MappedFieldPerceroObject) nextMappedField); - - 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); - } - - if (oneToMany != null) { - ((MappedFieldList) nextMappedField).setListClass(oneToMany.targetEntity()); - } - 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); - } - } + handleAnnotation_OneToMany(nextField, theGetter, nextMappedField); + handleAnnotation_ManyToOne(nextField, theGetter, nextMappedField); + handleAnnotation_OneToOne(nextField, theGetter, nextMappedField); Boolean isPropertyField = true; - Entity nextEntity = (Entity) nextField.getType().getAnnotation( - Entity.class); - if (nextEntity != null) { + if (nextField.getType().isAnnotationPresent(Entity.class)) { +// if (hasAnnotation(nextField.getType(), null, Entity.class)) { entityFields.add(nextField); toOneFields.add((MappedFieldPerceroObject) nextMappedField); isPropertyField = false; @@ -585,153 +544,285 @@ else if (implementsInterface(nextFieldClass, List.class)) propertyFields.add(nextMappedField); } - Id id = (Id) theGetter.getAnnotation(Id.class); - if (id == null) - id = (Id) nextField.getAnnotation(Id.class); - if (id != null) { - 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); - hasGeneratedId = (generatedValue != null); - } + handleAnnotation_Id(nextField, theGetter, nextMappedField); + handleAnnotation_Column(nextField, theGetter, nextMappedField); + handleAnnotation_JoinColumn(nextField, theGetter, nextMappedField); + handleAnnotation_AccessRights(nextField, theGetter, nextMappedField); - Column column = (Column) theGetter.getAnnotation(Column.class); - if (column == null) - column = (Column) nextField.getAnnotation(Column.class); - if (column != null) { - if (column.unique()) { - List uniqueConstraintList = new ArrayList( - 1); - uniqueConstraintList.add(nextMappedField); - uniqueConstraints.add(uniqueConstraintList); - } + // Check to see if this has any PropertyInterfaces that need to + // be addressed. + handleAnnotation_PropertyInterface(nextField, theGetter, nextMappedField); + handleAnnotation_PropertyInterfaces(nextField, theGetter, nextMappedField); + } + } catch (Exception e) { + logger.error("Error parsing MappedClass " + this.className, e); + } + fieldsInitialized = true; + } - if (column.name() != null - && column.name().trim().length() > 0) - nextMappedField.setColumnName(column.name()); - else - nextMappedField.setColumnName(nextField.getName()); - } + /** + * @param nextField + * @param theGetter + * @param nextMappedField + * @return + */ + protected PropertyInterfaces handleAnnotation_PropertyInterfaces(Field nextField, Method theGetter, + MappedField nextMappedField) { + PropertyInterfaces propertyInterfaces = retrieveAnnotation(nextField, theGetter, PropertyInterfaces.class); + if (propertyInterfaces != null) { + for (PropertyInterface nextPropInterface : propertyInterfaces.propertyInterfaces()) { + processMappedFieldPropertyInterface(nextPropInterface, nextMappedField); + } + } + return propertyInterfaces; + } - 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()); - } - } + /** + * @param nextField + * @param theGetter + * @param nextMappedField + * @return + */ + protected PropertyInterface handleAnnotation_PropertyInterface(Field nextField, Method theGetter, + MappedField nextMappedField) { + PropertyInterface propInterface = retrieveAnnotation(nextField, theGetter, PropertyInterface.class); + if (propInterface != null) { + processMappedFieldPropertyInterface(propInterface, nextMappedField); + } + return propInterface; + } - // Get NamedQueries for handling Access Rights. - AccessRights accessRights = (AccessRights) nextField - .getAnnotation(AccessRights.class); - if (accessRights == null) - accessRights = (AccessRights) nextMappedField.getGetter() - .getAnnotation(AccessRights.class); - if (accessRights != null) { - for (AccessRight nextAccessRight : accessRights.value()) { - /* - * if - * (nextAccessRight.type().equalsIgnoreCase("createQuery" - * )) { if (nextAccessRight.query().indexOf("jpql:") >= - * 0) nextMappedField.createQuery = new JpqlQuery(); - * else nextMappedField.createQuery = new MappedQuery(); - * nextMappedField - * .createQuery.setQuery(nextAccessRight.query()); } - * else if - * (nextAccessRight.type().equalsIgnoreCase("updateQuery" - * )) { if (nextAccessRight.query().indexOf("jpql:") >= - * 0) nextMappedField.updateQuery = new JpqlQuery(); - * else nextMappedField.updateQuery = new MappedQuery(); - * nextMappedField - * .updateQuery.setQuery(nextAccessRight.query()); } - * else - */ - if (nextAccessRight.type() - .equalsIgnoreCase("readQuery")) { - if (nextAccessRight.query().indexOf("jpql:") >= 0) { - nextMappedField.setReadQuery(new JpqlQuery()); - 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" - * )) { if (nextAccessRight.query().indexOf("jpql:") >= - * 0) nextMappedField.deleteQuery = new JpqlQuery(); - * else nextMappedField.deleteQuery = new MappedQuery(); - * nextMappedField - * .deleteQuery.setQuery(nextAccessRight.query()); } - */ + /** + * @param nextField + * @param theGetter + * @param nextMappedField + * @return + */ + protected OneToOne handleAnnotation_OneToOne(Field nextField, Method theGetter, MappedField nextMappedField) { + OneToOne oneToOne = retrieveAnnotation(nextField, theGetter, OneToOne.class); + if (oneToOne != null) { + if (StringUtils.hasText(oneToOne.mappedBy())) { + getTargetMappedFields().add(nextMappedField); + } else { + getSourceMappedFields().add((MappedFieldPerceroObject) nextMappedField); + } + } + return oneToOne; + } - // Add to queries list. - IMappedQuery nextQuery = null; - if (nextAccessRight.query().indexOf("jpql:") >= 0) { - nextQuery = new JpqlQuery(); - 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()); + /** + * @param nextField + * @param theGetter + * @param nextMappedField + */ + protected void handleAnnotation_ManyToOne(Field nextField, Method theGetter, MappedField nextMappedField) { + if (hasAnnotation(nextField, theGetter, ManyToOne.class)) { + getSourceMappedFields().add((MappedFieldPerceroObject) nextMappedField); + } + } - nextMappedField.queries.add(nextQuery); - } - } + /** + * @param nextField + * @param theGetter + * @param nextMappedField + * @return + */ + protected OneToMany handleAnnotation_OneToMany(Field nextField, Method theGetter, MappedField nextMappedField) { + OneToMany oneToMany = retrieveAnnotation(nextField, theGetter, OneToMany.class); + if (oneToMany != null) { + toManyFields.add(nextMappedField); + getTargetMappedFields().add(nextMappedField); + ((MappedFieldList) nextMappedField).setListClass(oneToMany.targetEntity()); + } + return oneToMany; + } - // Check to see if this has any PropertyInterfaces that need to - // be addresed. - PropertyInterface propInterface = (PropertyInterface) nextField - .getAnnotation(PropertyInterface.class); - if (propInterface != null) { - processMappedFieldPropertyInterface(propInterface, - nextMappedField); - } - PropertyInterfaces propertyInterfaces = (PropertyInterfaces) nextField - .getAnnotation(PropertyInterfaces.class); - if (propertyInterfaces != null) { - for (PropertyInterface nextPropInterface : propertyInterfaces - .propertyInterfaces()) { - processMappedFieldPropertyInterface(nextPropInterface, - nextMappedField); + /** + * @param nextField + * @param theGetter + * @param nextMappedField + */ + protected void handleAnnotation_Id(Field nextField, Method theGetter, MappedField nextMappedField) { + if (hasAnnotation(nextField, theGetter, Id.class)) { + idMappedField = nextMappedField; + + List uniqueConstraintList = new ArrayList(1); + uniqueConstraintList.add(nextMappedField); + uniqueConstraints.add(uniqueConstraintList); + + // Check to see if this class has a Generated ID. + hasGeneratedId = hasAnnotation(nextField, theGetter, GeneratedValue.class); + } + } + + /** + * @param nextField + * @param theGetter + * @param nextMappedField + * @return + */ + protected JoinColumn handleAnnotation_JoinColumn(Field nextField, Method theGetter, MappedField nextMappedField) { + JoinColumn joinColumn = retrieveAnnotation(nextField, theGetter, JoinColumn.class); + if (joinColumn != null) { + if (StringUtils.hasText(joinColumn.name())) { + nextMappedField.setJoinColumnName(joinColumn.name()); + } + } + return joinColumn; + } + + /** + * @param nextField + * @param theGetter + * @param nextMappedField + * @return + */ + protected Column handleAnnotation_Column(Field nextField, Method theGetter, MappedField nextMappedField) { + Column column = retrieveAnnotation(nextField, theGetter, Column.class); + if (column != null) { + 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()); + } + return column; + } + + /** + * @param nextField + * @param theGetter + * @param nextMappedField + * @return + */ + protected AccessRights handleAnnotation_AccessRights(Field nextField, Method theGetter, MappedField nextMappedField) { + AccessRights accessRights = retrieveAnnotation(nextField, theGetter, AccessRights.class); + if (accessRights != null) { + // Get NamedQueries for handling Access Rights. + for (AccessRight nextAccessRight : accessRights.value()) { + /* + * if + * (nextAccessRight.type().equalsIgnoreCase("createQuery" + * )) { if (nextAccessRight.query().indexOf("jpql:") >= + * 0) nextMappedField.createQuery = new JpqlQuery(); + * else nextMappedField.createQuery = new MappedQuery(); + * nextMappedField + * .createQuery.setQuery(nextAccessRight.query()); } + * else if + * (nextAccessRight.type().equalsIgnoreCase("updateQuery" + * )) { if (nextAccessRight.query().indexOf("jpql:") >= + * 0) nextMappedField.updateQuery = new JpqlQuery(); + * else nextMappedField.updateQuery = new MappedQuery(); + * nextMappedField + * .updateQuery.setQuery(nextAccessRight.query()); } + * else + */ + if (nextAccessRight.type() + .equalsIgnoreCase("readQuery")) { + 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" + * )) { if (nextAccessRight.query().indexOf("jpql:") >= + * 0) nextMappedField.deleteQuery = new JpqlQuery(); + * else nextMappedField.deleteQuery = new MappedQuery(); + * nextMappedField + * .deleteQuery.setQuery(nextAccessRight.query()); } + */ + + // Add to queries list. + IMappedQuery nextQuery = null; + 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); } - } catch (Exception e) { - logger.error("Error parsing MappedClass " + this.className, e); } - fieldsInitialized = true; + return accessRights; + } + + /** + * @param mappedField + * @param annotationClass + * @return + */ + private T retrieveAnnotation(MappedField mappedField, Class annotationClass) { + if (mappedField != null) { + return retrieveAnnotation(mappedField.getField(), mappedField.getGetter(), annotationClass); + } + else { + return null; + } + } + + /** + * @param nextField + * @param theGetter + * @param annotationClass + * @return + */ + private T retrieveAnnotation(Field nextField, Method theGetter, Class annotationClass) { + T annotation = (theGetter != null ? theGetter.getAnnotation(annotationClass) : null); + if (annotation == null) + annotation = (nextField != null ? nextField.getAnnotation(annotationClass) : null); + return annotation; } + /** + * @param mappedField + * @param annotationClass + * @return + */ + private boolean hasAnnotation(MappedField mappedField, Class annotationClass) { + if (mappedField != null) { + return hasAnnotation(mappedField.getField(), mappedField.getGetter(), annotationClass); + } + else { + return false; + } + } + /** + * @param nextField + * @param theGetter + * @param annotationClass + * @return + */ + @SuppressWarnings("rawtypes") + private boolean hasAnnotation(Field nextField, Method theGetter, Class annotationClass) { + boolean result = (theGetter != null ? theGetter.isAnnotationPresent(annotationClass) : false); + if (!result) + result = (nextField != null ? nextField.isAnnotationPresent(annotationClass) : false); + return result; + } + private void processMappedFieldPropertyInterface( PropertyInterface propInterface, MappedField mappedField) { if (propInterface == null @@ -879,13 +970,7 @@ public void initializeQueries() { // Need to find the corresponding field. for (MappedField nextRefMappedField : referencedMappedClass.toManyFields) { if (nextRefMappedField instanceof MappedFieldList) { - OneToMany refOneToMany = nextRefMappedField - .getField().getAnnotation( - OneToMany.class); - if (refOneToMany == null) - refOneToMany = nextRefMappedField - .getGetter().getAnnotation( - OneToMany.class); + OneToMany refOneToMany = retrieveAnnotation(nextRefMappedField, OneToMany.class); if (refOneToMany != null && refOneToMany.targetEntity() @@ -904,13 +989,7 @@ public void initializeQueries() { break; } } else if (nextRefMappedField instanceof MappedFieldPerceroObject) { - OneToOne refOneToOne = nextRefMappedField - .getField().getAnnotation( - OneToOne.class); - if (refOneToOne == null) - refOneToOne = nextRefMappedField - .getGetter().getAnnotation( - OneToOne.class); + OneToOne refOneToOne = retrieveAnnotation(nextRefMappedField, OneToOne.class); if (refOneToOne != null && refOneToOne.targetEntity() @@ -1003,13 +1082,7 @@ public void initializeRelationships() { while (itrExternalizeFields.hasNext()) { MappedField nextMappedField = itrExternalizeFields.next(); - OneToMany oneToMany = (OneToMany) nextMappedField.getGetter() - .getAnnotation(OneToMany.class); - if (oneToMany == null) - oneToMany = (OneToMany) nextMappedField.getField() - .getAnnotation(OneToMany.class); - - if (oneToMany != null) { + if (hasAnnotation(nextMappedField, OneToMany.class)) { // // This must be a source MappedField // sourceMappedFields.add((MappedFieldPerceroObject) // nextMappedField); @@ -1034,35 +1107,8 @@ public void initializeRelationships() { } - 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); - // } - // } + ManyToOne manyToOne = retrieveAnnotation(nextMappedField, ManyToOne.class); + OneToOne oneToOne = retrieveAnnotation(nextMappedField, OneToOne.class); if (manyToOne != null && !manyToOne.optional() || oneToOne != null && !oneToOne.optional()) { @@ -1087,20 +1133,13 @@ public void initializeRelationships() { // Find the reverse field. for (MappedField nextRefMappedField : referencedMappedClass.toManyFields) { if (nextRefMappedField instanceof MappedFieldList) { - OneToMany refOneToMany = nextRefMappedField - .getField().getAnnotation(OneToMany.class); - if (refOneToMany == null) - refOneToMany = nextRefMappedField.getGetter() - .getAnnotation(OneToMany.class); + OneToMany refOneToMany = retrieveAnnotation(nextRefMappedField, OneToMany.class); if (refOneToMany != null) { - Boolean inheritsFrom = - inheritsFrom(this.clazz, - refOneToMany.targetEntity()); - if (inheritsFrom && - nextMappedField.getField().getName().equals(refOneToMany.mappedBy())) - { + Boolean inheritsFrom = inheritsFrom(this.clazz, refOneToMany.targetEntity()); + if (inheritsFrom + && nextMappedField.getField().getName().equals(refOneToMany.mappedBy())) { // if (this.clazz == refOneToMany.targetEntity() // && nextMappedField // .getField() @@ -1112,11 +1151,7 @@ public void initializeRelationships() { } } } else if (nextRefMappedField instanceof MappedFieldPerceroObject) { - OneToOne refOneToOne = nextRefMappedField - .getField().getAnnotation(OneToOne.class); - if (refOneToOne == null) - refOneToOne = nextRefMappedField.getGetter() - .getAnnotation(OneToOne.class); + OneToOne refOneToOne = retrieveAnnotation(nextRefMappedField, OneToOne.class); if (refOneToOne != null) { Boolean inheritsFrom = @@ -1140,13 +1175,7 @@ public void initializeRelationships() { // Find the reverse field. for (MappedField nextRefMappedField : referencedMappedClass.toOneFields) { if (nextRefMappedField instanceof MappedFieldPerceroObject) { - OneToOne refOneToOne = nextRefMappedField - .getField().getAnnotation( - OneToOne.class); - if (refOneToOne == null) - refOneToOne = nextRefMappedField - .getGetter().getAnnotation( - OneToOne.class); + OneToOne refOneToOne = retrieveAnnotation(nextRefMappedField, OneToOne.class); if (refOneToOne != null) { if (StringUtils.hasText(refOneToOne.mappedBy())) { @@ -1194,7 +1223,7 @@ public void initializeRelationships() { } } } - referencedMappedClass.cascadeRemoveFieldReferences.put( + referencedMappedClass.addCascadeRemoveFieldReferences( nextMappedField, reverseMappedField); } @@ -1220,11 +1249,7 @@ public void initializeRelationships() { // Find the reverse field. for (MappedField nextRefMappedField : referencedMappedClass.toManyFields) { if (nextRefMappedField instanceof MappedFieldList) { - OneToMany refOneToMany = nextRefMappedField - .getField().getAnnotation(OneToMany.class); - if (refOneToMany == null) - refOneToMany = nextRefMappedField.getGetter() - .getAnnotation(OneToMany.class); + OneToMany refOneToMany = retrieveAnnotation(nextRefMappedField, OneToMany.class); if (refOneToMany != null) { Boolean inheritsFrom = @@ -1244,11 +1269,7 @@ public void initializeRelationships() { } } } else if (nextRefMappedField instanceof MappedFieldPerceroObject) { - OneToOne refOneToOne = nextRefMappedField - .getField().getAnnotation(OneToOne.class); - if (refOneToOne == null) - refOneToOne = nextRefMappedField.getGetter() - .getAnnotation(OneToOne.class); + OneToOne refOneToOne = retrieveAnnotation(nextRefMappedField, OneToOne.class); if (refOneToOne != null) { if (StringUtils.hasText(refOneToOne.mappedBy())) { @@ -1282,13 +1303,7 @@ public void initializeRelationships() { // Find the reverse field. for (MappedField nextRefMappedField : referencedMappedClass.toOneFields) { if (nextRefMappedField instanceof MappedFieldPerceroObject) { - OneToOne refOneToOne = nextRefMappedField - .getField().getAnnotation( - OneToOne.class); - if (refOneToOne == null) - refOneToOne = nextRefMappedField - .getGetter().getAnnotation( - OneToOne.class); + OneToOne refOneToOne = retrieveAnnotation(nextRefMappedField, OneToOne.class); if (refOneToOne != null) { // Boolean inheritsFrom = @@ -1297,13 +1312,8 @@ public void initializeRelationships() { // if (inheritsFrom && // nextMappedField.getField().getName().equals(refOneToOne.mappedBy())) // { - if (this.clazz == nextRefMappedField - .getField().getType() - && nextMappedField - .getField() - .getName() - .equals(refOneToOne - .mappedBy())) { + if (this.clazz == nextRefMappedField.getField().getType() + && nextMappedField.getField().getName().equals(refOneToOne.mappedBy())) { // Found the referenced field. reverseMappedField = nextRefMappedField; break; @@ -1329,8 +1339,8 @@ public void initializeRelationships() { } } } - referencedMappedClass.nulledOnRemoveFieldReferences - .put(nextMappedField, reverseMappedField); + referencedMappedClass.addNulledOnRemoveFieldReferences + (nextMappedField, reverseMappedField); readAccessRightsFieldReferences.add(nextMappedField); } @@ -1339,14 +1349,12 @@ public void initializeRelationships() { // Check to see if this has any RelationshipInterfaces that need // to be addresed. - RelationshipInterface propInterface = (RelationshipInterface) nextMappedField - .getField().getAnnotation(RelationshipInterface.class); - if (propInterface != null) { - processMappedFieldRelationshipInterface(propInterface, + RelationshipInterface relationshipInterface = retrieveAnnotation(nextMappedField, RelationshipInterface.class); + if (relationshipInterface != null) { + processMappedFieldRelationshipInterface(relationshipInterface, nextMappedField); } - RelationshipInterfaces relationshipInterfaces = (RelationshipInterfaces) nextMappedField - .getField().getAnnotation(RelationshipInterfaces.class); + RelationshipInterfaces relationshipInterfaces = retrieveAnnotation(nextMappedField, RelationshipInterfaces.class); if (relationshipInterfaces != null) { for (RelationshipInterface nextPropInterface : relationshipInterfaces .relationshipInterfaces()) { @@ -1380,6 +1388,36 @@ public void initializeRelationships() { relationshipsInitialized = true; } + private void addCascadeRemoveFieldReferences(MappedField nextMappedField, MappedField reverseMappedField) { + cascadeRemoveFieldReferences.put(nextMappedField, reverseMappedField); + } + + public Map getNulledOnRemoveFieldReferences() { + Map result = new HashMap(this.nulledOnRemoveFieldReferences.size()); + MappedClass mappedClass = this; + while (mappedClass != null) { + result.putAll(mappedClass.nulledOnRemoveFieldReferences); + mappedClass = mappedClass.parentMappedClass; + } + + return result; + } + + public Map getCascadeRemoveFieldReferences() { + Map result = new HashMap(this.cascadeRemoveFieldReferences.size()); + MappedClass mappedClass = this; + while (mappedClass != null) { + result.putAll(mappedClass.cascadeRemoveFieldReferences); + mappedClass = mappedClass.parentMappedClass; + } + + return result; + } + + private void addNulledOnRemoveFieldReferences(MappedField nextMappedField, MappedField reverseMappedField) { + nulledOnRemoveFieldReferences.put(nextMappedField, reverseMappedField); + } + private void processMappedFieldRelationshipInterface( RelationshipInterface relInterface, MappedField mappedField) { if (relInterface == null @@ -1774,5 +1812,11 @@ public MappedClassMethodPair(MappedClass mappedClass, Method method) { this.method = method; } } - + + public IPerceroObject newPerceroObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException { + IPerceroObject result = null; + result = (IPerceroObject) clazz.newInstance(); + return result; + } + } 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 95598a0..79927eb 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedClassManager.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedClassManager.java @@ -1,13 +1,13 @@ package com.percero.agents.sync.metadata; import java.util.Collection; -import java.util.HashMap; import java.util.Map; import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; public class MappedClassManager implements IMappedClassManager { - private Map mappedClassesByName = new HashMap(); + private Map mappedClassesByName = new ConcurrentHashMap(); public void addMappedClass(MappedClass theMappedClass) { if (!mappedClassesByName.containsKey(theMappedClass.className)) 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 726655b..b6671da 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedField.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedField.java @@ -3,6 +3,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.percero.framework.metadata.IMappedQuery; +import com.percero.framework.vo.IPerceroObject; import java.io.IOException; import java.io.ObjectInput; @@ -26,7 +27,22 @@ public class MappedField { private Boolean hasReadAccessRights = false; protected MappedField reverseMappedField = null; + private boolean reverseMappedFieldValid = false; public MappedField getReverseMappedField() { + if (!reverseMappedFieldValid && reverseMappedField == null) { + MappedClass mc = this.getMappedClass(); + if (mc.parentMappedClass != null) { + MappedField mf = mc.parentMappedClass.getMappedFieldByName(this.getField().getName()); + + // If mf is null it means that this Mapped Field is NOT defined on the corresponding mapped class. + if (mf != null) { + MappedField reverseMappedField = mf.getReverseMappedField(); + this.reverseMappedField = reverseMappedField; + } + } + + reverseMappedFieldValid = true; + } return reverseMappedField; } @@ -209,4 +225,15 @@ else if (mfObj.getMappedClass() == null || this.getMappedClass() == null) return this.getMappedClass().equals(mfObj.getMappedClass()); } } + + public void setToNull(IPerceroObject perceroObject) throws IllegalArgumentException, IllegalAccessException { + boolean isAccessible = getField().isAccessible(); + if (!isAccessible) { + getField().setAccessible(true); + } + getField().set(perceroObject, null); + if (!isAccessible) { + getField().setAccessible(false); + } + } } 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 f4d314a..c0b2288 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedFieldList.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedFieldList.java @@ -14,11 +14,14 @@ public class MappedFieldList extends MappedField { + @SuppressWarnings("rawtypes") private Class listClass = null; + @SuppressWarnings("rawtypes") public Class getListClass() { return listClass; } + @SuppressWarnings("rawtypes") public void setListClass(Class listClass) { this.listClass = listClass; } @@ -62,6 +65,7 @@ public Boolean isValueSetForQuery(Object anObject) throws IllegalArgumentExcepti return (value != null && !value.isEmpty()); } + @SuppressWarnings("rawtypes") 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/MappedQuery.java b/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java index 7b990bd..9422c7b 100644 --- a/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java +++ b/src/main/java/com/percero/agents/sync/metadata/MappedQuery.java @@ -7,7 +7,7 @@ import java.util.Map; import org.apache.log4j.Logger; -import org.hibernate.engine.query.ParamLocationRecognizer; +import org.hibernate.engine.query.spi.ParamLocationRecognizer; import org.springframework.util.StringUtils; import com.percero.framework.metadata.IMappedQuery; 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 2a5afeb..27b0699 100644 --- a/src/main/java/com/percero/agents/sync/metadata/QueryFactory.java +++ b/src/main/java/com/percero/agents/sync/metadata/QueryFactory.java @@ -5,11 +5,7 @@ public class QueryFactory { public static IMappedQuery createQuery(String query){ IMappedQuery result = null; - if (query.indexOf("jpql:") >= 0) { - result = new JpqlQuery(); - result.setQuery(query); - } - else if (query.indexOf("sql:") >= 0) { + if (query.indexOf("sql:") >= 0) { result = new SqlQuery(query.substring(query.indexOf("sql:")+4)); } else { 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 80c94ac..dd598bf 100644 --- a/src/main/java/com/percero/agents/sync/services/AccessorService.java +++ b/src/main/java/com/percero/agents/sync/services/AccessorService.java @@ -51,7 +51,6 @@ public Object getVersion() { } public Object pushMessage(String userId, String userToken, String deviceId, String className, String classId, Object message) { -// getSessionManager().putObject(theObject, user) return 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 82464d8..fecdada 100644 --- a/src/main/java/com/percero/agents/sync/services/DAODataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/DAODataProvider.java @@ -1,5 +1,6 @@ package com.percero.agents.sync.services; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; @@ -14,12 +15,9 @@ 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.JsonParseException; +import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.hibernate.PropertyValueException; import org.hibernate.Query; @@ -46,6 +44,12 @@ import com.percero.agents.sync.vo.IJsonObject; import com.percero.framework.vo.IPerceroObject; import com.percero.framework.vo.PerceroList; +import com.percero.serial.JsonUtils; + +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtField; +import javassist.CtMethod; @Component public class DAODataProvider implements IDataProvider { @@ -88,32 +92,43 @@ public void setDataProviderManager(IDataProviderManager value) { @SuppressWarnings({ "unchecked" }) - // TODO: @Transactional(readOnly=true) public PerceroList getAllByName(String className, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception { IDataAccessObject dao = (IDataAccessObject) DAORegistry.getInstance().getDataAccessObject(className); PerceroList results = dao.getAll(pageNumber, pageSize, returnTotal, userId, false); + List resultsToCache = new ArrayList(); 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 the object is in the cache, then we can use that instead of querying the database AGAIN for related objects. + IPerceroObject cachedResult = retrieveCachedObject(BaseDataObject.toClassIdPair(nextResult)); + if (cachedResult != null) { + results.set(results.indexOf(nextResult), cachedResult); + nextResult = cachedResult; + setObjectExpiration(nextResult); + } + else { + try { + populateToManyRelationships(nextResult, true, null); + populateToOneRelationships(nextResult, true, null); + resultsToCache.add(nextResult); + } catch (IllegalArgumentException e) { + throw new SyncDataException(e); + } catch (IllegalAccessException e) { + throw new SyncDataException(e); + } catch (InvocationTargetException e) { + throw new SyncDataException(e); + } } } } - putObjectsInRedisCache(results); + // We only need to put non-cached results into the cache. + if (!resultsToCache.isEmpty()) { + putObjectsInRedisCache(resultsToCache); + } // Now clean the objects for the user. List cleanedObjects = cleanObject(results, userId); @@ -141,7 +156,6 @@ public Set getAllClassIdPairsByName(String className) throws Except } @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); @@ -236,26 +250,33 @@ protected static List processQueryResults(String resultClassName, Query public IPerceroObject findById(ClassIDPair classIdPair, String userId) { return findById(classIdPair, userId, false); } - @SuppressWarnings("unchecked") public IPerceroObject findById(ClassIDPair classIdPair, String userId, Boolean ignoreCache) { + return findById(classIdPair, userId, false, false); + } + @SuppressWarnings("unchecked") + public IPerceroObject findById(ClassIDPair classIdPair, String userId, Boolean ignoreCache, Boolean shellOnly) { try { IPerceroObject result = null; if (!ignoreCache) { - result = retrieveFromRedisCache(classIdPair); + result = retrieveFromRedisCache(classIdPair, shellOnly); } 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); + result = dao.retrieveObject(classIdPair, null, shellOnly); // Now put the object in the cache. if (result != null) { - populateToManyRelationships(result, true, null); - populateToOneRelationships(result, true, null); - putObjectInRedisCache(result); + if (!shellOnly) { + // Now need to populate relationships when only a shell object. + populateToManyRelationships(result, true, null); + populateToOneRelationships(result, true, null); + // We don't want to put a shell object in the cache. + putObjectInRedisCache(result, false); + } } else { // Not necessarily a problem but could be helpful when debugging. @@ -267,7 +288,9 @@ public IPerceroObject findById(ClassIDPair classIdPair, String userId, Boolean i setObjectExpiration(result); } - result = cleanObject(result, userId); + if (!shellOnly) { + result = cleanObject(result, userId); + } return result; } catch(Exception e) { @@ -278,15 +301,18 @@ public IPerceroObject findById(ClassIDPair classIdPair, String userId, Boolean i } - private void putObjectInRedisCache(IPerceroObject perceroObject) { + private void putObjectInRedisCache(IPerceroObject perceroObject, boolean onlyIfExists) { // 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); - String classKey = RedisKeyUtils.classIds(perceroObject.getClass().getCanonicalName()); - cacheDataStore.setSetValue(classKey, perceroObject.getID()); + if (!onlyIfExists || cacheDataStore.hasKey(key)) { + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + setObjectExpiration(key); + + String classKey = RedisKeyUtils.classIds(perceroObject.getClass().getCanonicalName()); + cacheDataStore.setSetValue(classKey, perceroObject.getID()); + } } } @@ -355,7 +381,7 @@ private void deleteObjectsFromRedisCache(List results) { } private void setObjectExpiration(IPerceroObject perceroObject) { - setObjectExpiration(RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID())); + setObjectExpiration(RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID())); } private void setObjectExpiration(String key) { @@ -367,11 +393,11 @@ private void setObjectExpiration(String key) { @Override public IPerceroObject retrieveCachedObject(ClassIDPair classIdPair) throws Exception { - return retrieveFromRedisCache(classIdPair); + return retrieveFromRedisCache(classIdPair, false); } @SuppressWarnings({ "rawtypes", "unchecked" }) - private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Exception { + private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair, boolean shellOnly) throws Exception { IPerceroObject result = null; if (cacheTimeout > 0) { IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); @@ -379,29 +405,44 @@ private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Ex 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); - } + // If we are only retrieving the shell object, then we really only care if the key exists. + if (shellOnly) { + if (cacheDataStore.hasKey(key)) { + result = (IPerceroObject) theClass.newInstance(); + result.setID(classIdPair.getID()); + } + else { + // Check MappedClass' child classes. + Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); + while (itrChildMappedClasses.hasNext()) { + MappedClass nextChildMc = itrChildMappedClasses.next(); + key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); + if (cacheDataStore.hasKey(key)) { + result = (IPerceroObject) nextChildMc.clazz.newInstance(); + result.setID(classIdPair.getID()); + break; + } + } + } } 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; - } - } + String jsonObjectString = (String) cacheDataStore.getValue(key); + if (jsonObjectString != null) { + result = createFromJson(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 = createFromJson(jsonObjectString, nextChildMc.clazz); + break; + } + } + } } } @@ -410,6 +451,18 @@ private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Ex } return result; } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected IPerceroObject createFromJson(String jsonObjectString, Class clazz) throws InstantiationException, IllegalAccessException, JsonParseException, JsonMappingException, IOException { + if (JsonUtils.isClassAssignableFromIJsonObject(clazz)) { + IJsonObject jsonObject = (IJsonObject) clazz.newInstance(); + jsonObject.fromJson(jsonObjectString); + return (IPerceroObject) jsonObject; + } + else { + return (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, clazz); + } + } @SuppressWarnings({ "rawtypes", "unchecked" }) private Map retrieveFromRedisCache(ClassIDPairs classIdPairs, Boolean pleaseSetTimeout) throws Exception { @@ -417,15 +470,14 @@ private Map retrieveFromRedisCache(ClassIDPairs classIdP 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()); + Map keys = new HashMap(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); + keys.put(nextKey, mc.clazz); // Check MappedClass' child classes. Iterator itrChildMappedClasses = mc.childMappedClasses.iterator(); @@ -436,51 +488,21 @@ private Map retrieveFromRedisCache(ClassIDPairs classIdP break; } nextKey = RedisKeyUtils.classIdPair(nextChildMc.className, nextId); - keys.add(nextKey); + keys.put(nextKey, nextChildMc.clazz); } } - -// 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(); + + for(Entry nextKeyClass : keys.entrySet()) { + String jsonObjectString = (String) cacheDataStore.getValue(nextKeyClass.getKey()); if (jsonObjectString != null) { - if (IJsonObject.class.isAssignableFrom(theClass)) { - IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); - jsonObject.fromJson(jsonObjectString); - if (jsonObject instanceof BaseDataObject) { - ((BaseDataObject) jsonObject).setDataSource(BaseDataObject.DATA_SOURCE_CACHE); - } - result.put( (((IPerceroObject) jsonObject).getID()), (IPerceroObject) jsonObject ); - } - else { - IPerceroObject nextPerceroObject = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); - - if (nextPerceroObject instanceof BaseDataObject) { - ((BaseDataObject) nextPerceroObject).setDataSource(BaseDataObject.DATA_SOURCE_CACHE); - } - result.put( nextPerceroObject.getID(), nextPerceroObject); - } - + IPerceroObject nextPerceroObject = createFromJson(jsonObjectString, nextKeyClass.getValue()); + ((BaseDataObject) nextPerceroObject).setDataSource(BaseDataObject.DATA_SOURCE_CACHE); + 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); + cacheDataStore.expire(keys.keySet(), cacheTimeout, TimeUnit.SECONDS); } } @@ -552,7 +574,6 @@ public List findByIds(ClassIDPairs classIdPairs, String userId, } catch(Exception e) { log.error(e); - e.printStackTrace(); } return results; @@ -563,31 +584,49 @@ public List findByIds(ClassIDPairs classIdPairs, String userId, 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); + List resultsToCache = new ArrayList(); 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 (!shellOnly) { + try { + // If the object is in the cache, then we can use that instead of querying the database AGAIN for related objects. + IPerceroObject cachedResult = retrieveCachedObject(BaseDataObject.toClassIdPair(nextResult)); + if (cachedResult != null) { + results.set(results.indexOf(nextResult), cachedResult); + nextResult = cachedResult; + setObjectExpiration(nextResult); + } + else { + populateToManyRelationships(nextResult, true, null); + populateToOneRelationships(nextResult, true, null); + + resultsToCache.add(nextResult); + } + } catch (IllegalArgumentException e) { + throw new SyncDataException(e); + } catch (IllegalAccessException e) { + throw new SyncDataException(e); + } catch (InvocationTargetException e) { + throw new SyncDataException(e); + } catch (Exception e) { + throw new SyncDataException(e); + } + } } } - putObjectsInRedisCache(results); - - // Now clean the objects for the user. - results = cleanObject(results, userId); + if (!shellOnly) { + if (!resultsToCache.isEmpty()) { + putObjectsInRedisCache(resultsToCache); + } + + // Now clean the objects for the user. + results = cleanObject(results, userId); + } return results; } @@ -605,82 +644,53 @@ public T createObject(T perceroObject, String userId) else { // Check to see if item already exists. try { - IPerceroObject existingObject = dao.retrieveObject(BaseDataObject.toClassIdPair(perceroObject), null, false); - if (existingObject != null) - { - populateToManyRelationships(perceroObject, true, null); - populateToOneRelationships(perceroObject, true, null); - return (T) cleanObject(perceroObject, userId); + // We want to see if this object already exists, we will + // check the cache first, then the database. + // We search without a UserID in the case that the object + // exists, but the user does NOT have access to + // it. Then we clean the object after retrieval (if it has + // been found) + IPerceroObject existingObject = findById(BaseDataObject.toClassIdPair(perceroObject), null); + if (existingObject != null) { + return (T) cleanObject(existingObject, userId); } } catch( Exception e) { log.debug("Error retrieving object on create", e); } } - - perceroObject = (T) dao.createObject(perceroObject, userId); - if (perceroObject == null) { - return perceroObject; + + // The incoming perceroObject will have all of it's source + // relationships filled (by definition, it can't have any target + // relationships yet since it is a new object). + + IPerceroObject createdPerceroObject = (T) dao.createObject(perceroObject, userId); + if (createdPerceroObject == null) { + // User must not have permission to create the object. + return null; } - populateToManyRelationships(perceroObject, true, null); - populateToOneRelationships(perceroObject, true, null); + + // Reset all the relationships in the case that dao.createObject removed them from the object. + overwriteToManyRelationships(createdPerceroObject, perceroObject); + overwriteToOneRelationships(createdPerceroObject, perceroObject); // 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()); - 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()); - } + putObjectInRedisCache(createdPerceroObject, false); + + // For each source related object, we need to handle the update + // by updating the cache. We only care about source mapped fields + // because those are the only ones that are possible to be present + // here since this is a new object. + for(MappedFieldPerceroObject nextSourceMappedField : mappedClass.getSourceMappedFields()) { + if (nextSourceMappedField.getReverseMappedField() != null) { + IPerceroObject relatedObject = (IPerceroObject) nextSourceMappedField.getValue(createdPerceroObject); + if (relatedObject != null) { + Collection reverseMappedFields = new ArrayList(1); + reverseMappedFields.add(nextSourceMappedField.getReverseMappedField()); + handleUpdatedClassIdPair(createdPerceroObject, BaseDataObject.toClassIdPair(relatedObject), reverseMappedFields, userId); + } + } + } } return (T) cleanObject(perceroObject, userId); @@ -707,52 +717,51 @@ else if (fieldObject instanceof Collection) { @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); + IPerceroObject updateResultObject = (T) dao.updateObject(perceroObject, changedFields, userId); + + if (updateResultObject == null) { + // The update failed, so we can return here. + return null; + } try { - populateToManyRelationships(perceroObject, true, null); - populateToOneRelationships(perceroObject, true, null); + // Overwrite the related objects. No need to go to the database since these could NOT have changed in this update. + overwriteToManyRelationships(updateResultObject, perceroObject); + overwriteToOneRelationships(updateResultObject, perceroObject); } catch (IllegalArgumentException e) { - e.printStackTrace(); - throw new SyncException(e); + throw new SyncDataException(SyncDataException.UPDATE_OBJECT_ERROR, SyncDataException.UPDATE_OBJECT_ERROR_CODE, e); } catch (IllegalAccessException e) { - e.printStackTrace(); - throw new SyncException(e); + throw new SyncException(SyncDataException.UPDATE_OBJECT_ERROR, SyncDataException.UPDATE_OBJECT_ERROR_CODE, e); } catch (InvocationTargetException e) { - e.printStackTrace(); - throw new SyncException(e); + throw new SyncException(SyncDataException.UPDATE_OBJECT_ERROR, SyncDataException.UPDATE_OBJECT_ERROR_CODE, 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()); - } + putObjectInRedisCache(updateResultObject, true); - List pairsToDelete = new ArrayList(); + List cachePairsToUpdate = new ArrayList(); // Iterate through each changed object and reset the cache for that object. if (changedFields != null) { - Iterator itrChangedFieldKeyset = changedFields.keySet().iterator(); - while (itrChangedFieldKeyset.hasNext()) { - ClassIDPair thePair = itrChangedFieldKeyset.next(); - if (!thePair.comparePerceroObject(perceroObject)) { - pairsToDelete.add(thePair); -// String nextKey = RedisKeyUtils.classIdPair(thePair.getClassName(), thePair.getID()); -// pairsToDelete.add(nextKey); - } - } + Iterator>> itrChangedFieldEntrySet = changedFields.entrySet().iterator(); + while (itrChangedFieldEntrySet.hasNext()) { + Entry> nextEntry = itrChangedFieldEntrySet.next(); + ClassIDPair thePair = nextEntry.getKey(); + Collection mappedFields = nextEntry.getValue(); + handleUpdatedClassIdPair(updateResultObject, thePair, mappedFields, userId); + } } else { + log.error("No Changed fields when updating object " + perceroObject.getClass().getCanonicalName() + "::" + perceroObject.getID()); // No changedFields? We should never get here? IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); + MappedClass mappedClass = mcm.getMappedClassByClassName(updateResultObject.getClass().getName()); Iterator itrToManyFields = mappedClass.toManyFields.iterator(); while(itrToManyFields.hasNext()) { MappedField nextMappedField = itrToManyFields.next(); Object fieldObject = null; try { - fieldObject = nextMappedField.getGetter().invoke(perceroObject); + fieldObject = nextMappedField.getGetter().invoke(updateResultObject); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { @@ -762,7 +771,7 @@ public T putObject(T perceroObject, Map void handleUpdatedClassIdPair(T originalUpdatedObject, ClassIDPair theRelatedObjectClassIdPair, + Collection mappedFields, String userId) { + + // Make sure that theRelatedClassIdPair is not the same as the original object + if (!theRelatedObjectClassIdPair.comparePerceroObject(originalUpdatedObject)) { + // This should contain at least one field, otherwise nothing as changed (most likely a one-way relationship). + if (mappedFields != null && !mappedFields.isEmpty()) { + IPerceroObject nextUpdatedCachedObject; + try { + nextUpdatedCachedObject = retrieveCachedObject(theRelatedObjectClassIdPair); + boolean cachedObjectUpdated = false; + + // If the related object is NOT in the cache, then we having nothing to do. + if (nextUpdatedCachedObject != null) { + for(MappedField nextMappedField : mappedFields) { + try { + if (nextMappedField.getMappedClass().toManyFields.contains(nextMappedField)) { + if (handleUpdatedClassIdPair_ToManyMappedField( + originalUpdatedObject, nextUpdatedCachedObject, nextMappedField, userId)) { + cachedObjectUpdated = true; + } + } + else if (nextMappedField.getMappedClass().toOneFields.contains(nextMappedField)) { + if (handleUpdatedClassIdPair_ToOneMappedField( + originalUpdatedObject, nextUpdatedCachedObject, nextMappedField, userId)) { + cachedObjectUpdated = true; + } + } + } catch(Exception e) { + log.error("Unable to retrieve related objects for " + originalUpdatedObject.getClass().getCanonicalName() + "::" + nextMappedField.getField().getName()); + } + } + + if (cachedObjectUpdated) { + // Update the cached object. + putObjectInRedisCache(nextUpdatedCachedObject, false); + } + } + } catch (Exception e) { + log.error("Error updating related object " + theRelatedObjectClassIdPair.toJson(), e); + } + } + } + } + + /** + * @param originalUpdatedObject + * @param currentRelatedObject + * @param relatedMappedField + * @param userId + * @return + * @throws IllegalAccessException + * @throws InvocationTargetException + * @throws SyncException + */ + @SuppressWarnings("unchecked") + private boolean handleUpdatedClassIdPair_ToManyMappedField(T originalUpdatedObject, + IPerceroObject currentRelatedObject, MappedField relatedMappedField, String userId) + throws IllegalAccessException, InvocationTargetException, SyncException { + boolean cachedObjectUpdated = false; + + IPerceroObject newRelatedObject = (IPerceroObject) (relatedMappedField.getReverseMappedField() != null ? relatedMappedField.getReverseMappedField().getGetter().invoke(originalUpdatedObject) : null); + if (newRelatedObject != null) { + List updatedList = (List) relatedMappedField.getGetter().invoke(currentRelatedObject); + if (updatedList == null) { + updatedList = new ArrayList(); + relatedMappedField.getSetter().invoke(currentRelatedObject, updatedList); + } + + // Find the index of the original object in this related mapped list, if it exists. + int collectionIndex = findPerceroObjectInList(originalUpdatedObject, + updatedList); + + if (BaseDataObject.toClassIdPair(currentRelatedObject).comparePerceroObject(newRelatedObject)) { + // The perceroObject has been ADDED to the list. + if (collectionIndex < 0) { + // Only add the perceroObject to the Collection if it is NOT already there. + updatedList.add(originalUpdatedObject); + cachedObjectUpdated = true; + } + } + else { + // The perceroObject has been REMOVED from the list. + if (collectionIndex >= 0){ + updatedList.remove(collectionIndex); + cachedObjectUpdated = true; + } + } + } + else { + // We are unable to get a hold of the reverse mapped field, so we default back to the underlying data store. + List allRelatedObjects = findAllRelatedObjects(currentRelatedObject, relatedMappedField, true, userId); + relatedMappedField.getSetter().invoke(currentRelatedObject, allRelatedObjects); + cachedObjectUpdated = true; + } + return cachedObjectUpdated; + } + + /** + * @param originalUpdatedObject + * @param currentRelatedObject + * @param relatedMappedField + * @param userId + * @return + * @throws IllegalAccessException + * @throws InvocationTargetException + * @throws SyncException + */ + private boolean handleUpdatedClassIdPair_ToOneMappedField(T originalUpdatedObject, + IPerceroObject currentRelatedObject, MappedField relatedMappedField, String userId) + throws IllegalAccessException, InvocationTargetException, SyncException { + + boolean cachedObjectUpdated = false; + + IPerceroObject newRelatedObject = (IPerceroObject) (relatedMappedField.getReverseMappedField() != null ? relatedMappedField.getReverseMappedField().getGetter().invoke(originalUpdatedObject) : null); + if (newRelatedObject != null) { + IPerceroObject oldUpdatedObject = (IPerceroObject) relatedMappedField.getGetter().invoke(currentRelatedObject); + + if (BaseDataObject.toClassIdPair(currentRelatedObject).comparePerceroObject(newRelatedObject)) { + // If the newRelatedPerceroObject is the same as the + // currentRelatedPerceroObject, then we know that this is the NEW + // related object. + + // Only add the perceroObject to the Collection if it is NOT already there. + if (!BaseDataObject.toClassIdPair(originalUpdatedObject).comparePerceroObject(oldUpdatedObject)) { +// oldRelatedObject.add(originalUpdatedObject); + relatedMappedField.getSetter().invoke(currentRelatedObject, originalUpdatedObject); + cachedObjectUpdated = true; + } + } + else { + // Else, we know that this is the OLD related object. + // The perceroObject has been REMOVED from the list. + if (oldUpdatedObject != null) { +// oldRelatedObject.remove(collectionIndex); + boolean isAccessible = relatedMappedField.getField().isAccessible(); + if (!isAccessible) { + relatedMappedField.getField().setAccessible(true); + } + relatedMappedField.getField().set(currentRelatedObject, null); + if (!isAccessible) { + relatedMappedField.getField().setAccessible(false); + } + cachedObjectUpdated = true; + } + } + } + else { + // We are unable to get a hold of the reverse mapped field, so we default back to the underlying data store. + // We need to go to the dataProvider for the related object's class and ask for it. + // Though this returns a List, we expect there to be only one result in the list. + List allRelatedObjects = findAllRelatedObjects(currentRelatedObject, relatedMappedField, true, userId); + IPerceroObject relatedPerceroObject = null; + if (allRelatedObjects != null && !allRelatedObjects.isEmpty()) { + relatedPerceroObject = allRelatedObjects.get(0); + } + relatedMappedField.getSetter().invoke(currentRelatedObject, relatedPerceroObject); + cachedObjectUpdated = true; + } + return cachedObjectUpdated; +// +// boolean cachedObjectUpdated; +// // We need to go to the dataProvider for the related object's class and ask for it. +// // Though this returns a List, we expect there to be only one result in the list. +// List allRelatedObjects = findAllRelatedObjects(currentRelatedObject, relatedMappedField, true, userId); +// IPerceroObject relatedPerceroObject = null; +// if (allRelatedObjects != null && !allRelatedObjects.isEmpty()) { +// relatedPerceroObject = allRelatedObjects.get(0); +// } +// relatedMappedField.getSetter().invoke(currentRelatedObject, relatedPerceroObject); +// cachedObjectUpdated = true; +// return cachedObjectUpdated; + } + + /** + * @param originalUpdatedObject + * @param updatedList + * @return + */ + protected int findPerceroObjectInList(T originalUpdatedObject, + List updatedList) { + int index = 0; + Iterator itrUpdatedCollection = updatedList.iterator(); + ClassIDPair perceroIdPair = BaseDataObject.toClassIdPair(originalUpdatedObject); + + while (itrUpdatedCollection.hasNext()) { + IPerceroObject nextCollectionObject = itrUpdatedCollection.next(); + if (perceroIdPair.comparePerceroObject(nextCollectionObject)) { + return index; + } + index++; + } + + return -1; + } + //////////////////////////////////////////////////// // DELETE //////////////////////////////////////////////////// - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({ "unchecked" }) public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws SyncException { if (theClassIdPair == null || !StringUtils.hasText(theClassIdPair.getID())) { @@ -853,96 +1076,111 @@ public Boolean deleteObject(ClassIDPair theClassIdPair, String userId) throws Sy } 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); + IPerceroObject originalDeletedObject = dao.retrieveObject(theClassIdPair, null, false); // Retrieve the full object so we can update the cache if the delete is successful. - if (perceroObject == null) { + if (originalDeletedObject == null) { + // If the object already does NOT exist, then there is nothing to do. return true; } + + Boolean result = dao.deleteObject(theClassIdPair, userId); try { - MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(perceroObject.getClass().getCanonicalName()); + MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(originalDeletedObject.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 ); + log.warn("Missing MappedClass for " + originalDeletedObject.getClass().getCanonicalName()); + throw new SyncException(SyncException.MISSING_MAPPED_CLASS_ERROR, SyncException.MISSING_MAPPED_CLASS_ERROR_CODE); } // 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 (result && cacheTimeout > 0) { - List objectsToDelete = new ArrayList(); - -// String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); - objectsToDelete.add(BaseDataObject.toClassIdPair(perceroObject)); - 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) { - objectsToDelete.add(BaseDataObject.toClassIdPair((IPerceroObject)fieldObject)); -// String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); -// objectsToDelete.add(nextKey); - } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - objectsToDelete.add(BaseDataObject.toClassIdPair((IPerceroObject) nextListObject)); -// String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); -// objectsToDelete.add(nextKey); - } - } - } - } + handleDeletedClassIDPair_MappedField(originalDeletedObject, itrToManyFields.next()); } 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) { - objectsToDelete.add(BaseDataObject.toClassIdPair((IPerceroObject) fieldObject)); -// String nextKey = RedisKeyUtils.classIdPair(fieldObject.getClass().getCanonicalName(), ((IPerceroObject)fieldObject).getID()); -// objectsToDelete.add(nextKey); - } - else if (fieldObject instanceof Collection) { - Iterator itrFieldObject = ((Collection) fieldObject).iterator(); - while(itrFieldObject.hasNext()) { - Object nextListObject = itrFieldObject.next(); - if (nextListObject instanceof IPerceroObject) { - objectsToDelete.add(BaseDataObject.toClassIdPair((IPerceroObject) nextListObject)); -// String nextKey = RedisKeyUtils.classIdPair(nextListObject.getClass().getCanonicalName(), ((IPerceroObject)nextListObject).getID()); -// objectsToDelete.add(nextKey); - } - } - } - } + handleDeletedClassIDPair_MappedField(originalDeletedObject, itrToOneFields.next()); } - if (!objectsToDelete.isEmpty()) { - deleteObjectsFromRedisCache(objectsToDelete); -// cacheDataStore.deleteKeys(objectsToDelete); - } + deleteObjectFromRedisCache(BaseDataObject.toClassIdPair(originalDeletedObject)); } } 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); + throw new SyncDataException(SyncDataException.DELETE_OBJECT_ERROR, SyncDataException.DELETE_OBJECT_ERROR_CODE, e); } return result; } + /** + * @param originalDeletedObject + * @param itrToOneFields + * @return + * @throws Exception + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private boolean handleDeletedClassIDPair_MappedField(IPerceroObject originalDeletedObject, + MappedField mappedField) + throws Exception { + + if (mappedField == null) { + return false; + } + if (mappedField.getReverseMappedField() == null) { + // Nothing to do since the related object does not know about the relationship. + return true; + } + + Object fieldObject = mappedField.getGetter().invoke(originalDeletedObject); + + // We only need to update this related object(s) if it is set. + if (fieldObject != null) { + if (fieldObject instanceof IPerceroObject) { + fieldObject = retrieveCachedObject(BaseDataObject.toClassIdPair((IPerceroObject) fieldObject)); + Object theRelatedObject = mappedField.getReverseMappedField().getGetter().invoke(fieldObject); + if (theRelatedObject != null) { + if (theRelatedObject instanceof IPerceroObject) { + // Since the value is set, un-set it and save back to to the data store. + mappedField.getReverseMappedField().setToNull((IPerceroObject) fieldObject); + putObjectInRedisCache((IPerceroObject) fieldObject, true); + } + else if (theRelatedObject instanceof List) { + int i = 0; + for(IPerceroObject nextRelatedObject : (List) theRelatedObject) { + if (BaseDataObject.toClassIdPair(originalDeletedObject).comparePerceroObject(nextRelatedObject)) { + ((List) theRelatedObject).remove(i); + break; + } + i++; + } + putObjectInRedisCache((IPerceroObject) fieldObject, true); + } + } + } + else if (fieldObject instanceof Collection) { + Iterator itrFieldObject = ((Collection) fieldObject).iterator(); + while(itrFieldObject.hasNext()) { + Object nextListObject = itrFieldObject.next(); + if (nextListObject instanceof IPerceroObject) { + nextListObject = retrieveCachedObject(BaseDataObject.toClassIdPair((IPerceroObject) nextListObject)); + IPerceroObject theRelatedObject = (IPerceroObject) mappedField.getReverseMappedField().getGetter().invoke(nextListObject); + if (theRelatedObject != null) { + // Since the value is set, un-set it and save back to to the data store. + mappedField.getReverseMappedField().setToNull((IPerceroObject) nextListObject); + putObjectInRedisCache((IPerceroObject) nextListObject, true); + } + } + } + } + } + return true; + } + + //////////////////////////////////////////////////// // CLEAN //////////////////////////////////////////////////// @@ -1286,6 +1524,24 @@ public void populateToManyRelationships(IPerceroObject perceroObject, Boolean sh } } } + + protected void overwriteToManyRelationships(IPerceroObject perceroObject, IPerceroObject sourceObject) { + if (perceroObject == null || sourceObject == null) { + // Invalid object. + log.warn("Invalid object in overwriteToManyRelationships"); + return; + } + + MappedClass mappedClass = MappedClassManagerFactory.getMappedClassManager().getMappedClassByClassName(perceroObject.getClass().getCanonicalName()); + for(MappedField nextToManyMappedField : mappedClass.toManyFields) { + + try { + nextToManyMappedField.getSetter().invoke(perceroObject, nextToManyMappedField.getGetter().invoke(sourceObject)); + } catch(Exception e) { + log.error("Unable to retrieve related objects for " + perceroObject.getClass().getCanonicalName() + "::" + nextToManyMappedField.getField().getName()); + } + } + } public void populateToOneRelationships(IPerceroObject perceroObject, Boolean shellOnly, String userId) throws SyncException, IllegalArgumentException, @@ -1361,16 +1617,22 @@ public void populateToOneRelationships(IPerceroObject perceroObject, Boolean she } } } - -// 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); -// } -// } + + protected void overwriteToOneRelationships(IPerceroObject perceroObject, IPerceroObject sourceObject) throws SyncException, IllegalArgumentException, + IllegalAccessException, InvocationTargetException { + if (perceroObject == null || sourceObject == null) { + // Invalid object. + log.warn("Invalid object in overwriteToOneRelationships"); + 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()) { + nextToOneMappedField.getSetter().invoke(perceroObject, nextToOneMappedField.getGetter().invoke(sourceObject)); + } + } + } } diff --git a/src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java b/src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java deleted file mode 100644 index b962733..0000000 --- a/src/main/java/com/percero/agents/sync/services/HibernateDataProvider.java +++ /dev/null @@ -1,1688 +0,0 @@ -//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 ace4c59..3131032 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) throws SyncException; public IPerceroObject findById(ClassIDPair classIdPair, String userId); public IPerceroObject findById(ClassIDPair classIdPair, String userId, Boolean ignoreCache); + public IPerceroObject findById(ClassIDPair classIdPair, String userId, Boolean ignoreCache, Boolean shellOnly); public IPerceroObject retrieveCachedObject(ClassIDPair classIdPair) throws Exception; public List findByIds(ClassIDPairs classIdPairs, String userId); public List findByIds(ClassIDPairs classIdPairs, String userId, Boolean ignoreCache); diff --git a/src/main/java/com/percero/agents/sync/services/IPushSyncHelper.java b/src/main/java/com/percero/agents/sync/services/IPushSyncHelper.java index bf365aa..0565215 100644 --- a/src/main/java/com/percero/agents/sync/services/IPushSyncHelper.java +++ b/src/main/java/com/percero/agents/sync/services/IPushSyncHelper.java @@ -2,7 +2,9 @@ import java.util.Collection; +import com.percero.agents.sync.vo.ClassIDPair; import com.percero.agents.sync.vo.SyncResponse; +import com.percero.framework.vo.IPerceroObject; public interface IPushSyncHelper { @@ -17,4 +19,7 @@ public interface IPushSyncHelper { public Boolean removeClient(String clientId); public Boolean renameClient(String thePreviousClientId, String clientId); + void enqueueCheckChangeWatcher(ClassIDPair classIDPair, String[] fieldNames, String[] params); + void enqueueCheckChangeWatcher(ClassIDPair classIDPair, String[] fieldNames, String[] params, + IPerceroObject oldValue); } \ No newline at end of file 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 019477c..b33f29b 100644 --- a/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java +++ b/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java @@ -29,8 +29,8 @@ public interface ISyncAgentService { public ServerResponse deleteObject(ClassIDPair theClassIdPair, String clientId, Boolean pushToClient) throws Exception; public ServerResponse deleteObjectById(String theClassName, String theId, String clientId) throws Exception; public ServerResponse deleteObjectById(String theClassName, String theId, String clientId, Boolean pushToClient) throws Exception; - public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, boolean pushToUser) throws Exception; - public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, boolean pushToUser, Collection deletedObjects) throws Exception; + public boolean systemDeleteObject(ClassIDPair classIdPair, String clientId, boolean pushToUser) throws Exception; + public boolean systemDeleteObject(ClassIDPair classIdPair, String clientId, boolean pushToUser, Collection deletedObjects) throws Exception; public ServerResponse putObject(IPerceroObject perceroObject, String transactionId, Date updateDate, String clientId) throws Exception; public ServerResponse putObject(IPerceroObject perceroObject, String transactionId, Date updateDate, String clientId, Boolean pushToClient) 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 index a5634c3..b592fa5 100644 --- a/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/RedisDataProvider.java @@ -447,4 +447,10 @@ public Map> getChangedMappedFields( // TODO Auto-generated method stub return null; } + + @Override + public IPerceroObject findById(ClassIDPair classIdPair, String userId, Boolean ignoreCache, Boolean shellOnly) { + // 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 deleted file mode 100644 index cee4f85..0000000 --- a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java +++ /dev/null @@ -1,1698 +0,0 @@ -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 javax.annotation.PostConstruct; - -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.cache.CacheManager; -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 SyncAgentDataProvider implements IDataProvider { - - // TODO: Better manage Hibernate Sessions (opening and closing). - - private static final Logger log = Logger.getLogger(SyncAgentDataProvider.class); - - @PostConstruct - public void initialize() - { - // Do nothing. - DataProviderManager.getInstance().addDataProvider(this); - } - - public String getName() { - return "syncAgent"; - } - - @Autowired - ICacheDataStore cacheDataStore; - - @Autowired - Long cacheTimeout = Long.valueOf(60 * 60 * 24 * 14); // Two weeks - - @Autowired - CacheManager cacheManager; - - @Autowired - ObjectMapper safeObjectMapper; - - @Autowired - SessionFactory appSessionFactory; - public void setAppSessionFactory(SessionFactory value) { - appSessionFactory = value; - } - - - @SuppressWarnings({ "rawtypes", "unchecked" }) - // TODO: @Transactional(readOnly=true) - public PerceroList getAllByName(String className, Integer pageNumber, Integer pageSize, Boolean returnTotal, String userId) throws Exception { - Session s = appSessionFactory.openSession(); - try { - returnTotal = true; - Query countQuery = null; - Query query = null; - Class theClass = MappedClass.forName(className); - - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(className); - 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:"+className+". readAllQueries must be plain SQL. JPQL, HQL not supported yet. "); - } - log.debug("Using readAllQuery: "+className); - 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 " + 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) { - 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.getQueryString(), null, userId); - mappedClass.getReadQuery().setQueryParameters(countQuery.getQueryString(), 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: "+className); - - 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" }) - public Set getAllClassIdPairsByName(String className) throws Exception { - Set results = new HashSet(); - - Session s = appSessionFactory.openSession(); - try { - Query query = null; - - String queryString = "SELECT ID FROM " + className; - query = s.createQuery(queryString); - - List queryResults = query.list(); - Iterator itrQueryResults = queryResults.iterator(); - while (itrQueryResults.hasNext()) { - String nextId = (String) itrQueryResults.next(); - results.add(new ClassIDPair(nextId, className)); - } - - } catch (Exception e) { - log.error("Unable to getAllClassIdPairsByName", e); - } finally { - s.close(); - } - - return results; - } - - @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.getQueryString(), 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) 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" }) - 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; - } - - @Override - public IPerceroObject findById(ClassIDPair classIdPair, String userId) { - return findById(classIdPair, userId, false); - } - @Override - public IPerceroObject findById(ClassIDPair classIdPair, String userId, Boolean ignoreCache) { - 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, ignoreCache); - - if (result != null) { - if (hasReadQuery) { - if (s == null) - s = appSessionFactory.openSession(); - Query readFilter = s.createQuery(mappedClass.getReadQuery().getQuery()); - mappedClass.getReadQuery().setQueryParameters(readFilter.getQueryString(), 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; - } - - public IPerceroObject systemGetById(ClassIDPair classIdPair) { - return systemGetById(classIdPair, false); - } - - @SuppressWarnings({ "rawtypes" }) - public IPerceroObject systemGetById(ClassIDPair classIdPair, boolean ignoreCache) { - Session s = null; - try { - Class theClass = MappedClass.forName(classIdPair.getClassName().toString()); - - if (theClass != null) { - 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()); - 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; - } - - @Override - public IPerceroObject retrieveCachedObject(ClassIDPair classIdPair) throws Exception { - return retrieveFromRedisCache(classIdPair); - } - - @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.getQueryString(), 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.getQueryString(), 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; - } - - @Override - public List findByIds(ClassIDPairs classIdPairs, String userId) { - return findByIds(classIdPairs, userId, false); - } - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - public List findByIds(ClassIDPairs classIdPairs, String userId, Boolean ignoreCache) { - 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 = null; - if (!ignoreCache) { - cachedObjects = retrieveFromRedisCache(classIdPairs, true); - } - - if (cachedObjects != null && !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.getQueryString(), 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.getQueryString(), 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.getQueryString(), 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, Boolean shellOnly) { - 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()) { - 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; - } - 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); - } - } - } - } - - @SuppressWarnings("unchecked") - 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 { - IMappedQuery createQuery = mappedClass.getCreateQuery(); - Query createFilter = s.createQuery(mappedClass.getCreateQuery().getQuery()); - 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; - } 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 - //////////////////////////////////////////////////// - @SuppressWarnings("unchecked") - 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()); - 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.getQueryString(), 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 (T) systemPutObject(perceroObject, changedFields); - } else { - return null; - } - } - - 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. - 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 { - 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.getQueryString(), 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(); - } - } - - 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 and update related objects. - cacheManager.handleDeletedObject(perceroObject, SyncHibernateUtils.getShell(perceroObject).getClass().getName(), false); - - 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(); - } - } - } - - - public Map> getChangedMappedFields(IPerceroObject compareObject) { - return getChangedMappedFields(compareObject, false); - } - public Map> getChangedMappedFields(IPerceroObject compareObject, boolean ignoreCache) { - String className = compareObject.getClass().getCanonicalName(); - IPerceroObject oldObject = systemGetById(new ClassIDPair(compareObject.getID(), className), ignoreCache); - - return getChangedMappedFields(oldObject, compareObject, ignoreCache); - } - @SuppressWarnings("rawtypes") - public Map> getChangedMappedFields(IPerceroObject oldObject, IPerceroObject compareObject, boolean ignoreCache) { - Map> result = new HashMap>(); - - // Validate both objects. - if (oldObject == null || compareObject == null || oldObject.getID() == null || compareObject.getID() == null || !oldObject.getID().equals(compareObject.getID())) { - return result; - } - - Collection baseObjectResult = null; - ClassIDPair basePair = new ClassIDPair(compareObject.getID(), compareObject.getClass().getCanonicalName()); - - String className = compareObject.getClass().getCanonicalName(); - - 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, compareObject); - 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(compareObject); - 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(compareObject); - 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; - } - - - @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; - } - - 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 - 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 72f5505..bb40f22 100644 --- a/src/main/java/com/percero/agents/sync/services/SyncAgentService.java +++ b/src/main/java/com/percero/agents/sync/services/SyncAgentService.java @@ -1,5 +1,7 @@ package com.percero.agents.sync.services; +import java.io.IOException; + //import static org.springframework.data.mongodb.core.query.Criteria.where; import java.lang.reflect.InvocationTargetException; @@ -18,6 +20,8 @@ import javax.annotation.PostConstruct; import org.apache.log4j.Logger; +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -29,7 +33,6 @@ import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.access.RedisKeyUtils; -import com.percero.agents.sync.connectors.HttpConnectorOperation; import com.percero.agents.sync.connectors.ILogicConnector; import com.percero.agents.sync.cw.IChangeWatcherHelperFactory; import com.percero.agents.sync.cw.IChangeWatcherValueHelper; @@ -50,6 +53,8 @@ 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.rr.IRequestHandler; import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.ClassIDPair; @@ -255,7 +260,7 @@ public void processManifest() { public String getDataId(String clientId) throws Exception { Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); String dataId = (String) cacheDataStore.listIndex(RedisKeyUtils.dataRecord()); @@ -272,14 +277,11 @@ public PerceroList getAllByName(String className, Boolean return return getAllByName(className, null, null, returnTotal, clientId); } - @SuppressWarnings("rawtypes") 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); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); - 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(className); @@ -290,12 +292,9 @@ public PerceroList getAllByName(String className, Integer pageNu if (result != null) { // Register an Zero ID object to indicate that this user wants updates to ALL objects of this type. - Object newInstance = theClass.newInstance(); - if (newInstance instanceof IPerceroObject) { - ((IPerceroObject) newInstance).setID("0"); - - postGetHelper.postGetObject((IPerceroObject) newInstance, userId, clientId); - } + IPerceroObject newInstance = mappedClass.newPerceroObject(); + newInstance.setID("0"); + postGetHelper.postGetObject((IPerceroObject) newInstance, userId, clientId); } return result; @@ -307,7 +306,7 @@ public Map countAllByName(Collection classNames, String Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); Iterator itrClassNames = classNames.iterator(); while(itrClassNames.hasNext()) { @@ -332,7 +331,7 @@ public List runQuery(String className, String queryName, Object[] queryA Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); try { IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); @@ -353,7 +352,7 @@ public Object runProcess(String processName, Object queryArguments, String clien Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); if (!StringUtils.hasText(processName)) throw new SyncException(SyncException.INVALID_PROCESS_ERROR, SyncException.INVALID_PROCESS_ERROR_CODE); @@ -384,26 +383,49 @@ public Object runProcess(String processName, Object queryArguments, String clien if (processHelper != null) { try { - Object args[] = new Object[2]; - args[0] = clientId; - args[1] = queryArguments; - Method method = processHelper.getClass().getDeclaredMethod(processName, new Class[]{String.class,Object[].class}); - result = method.invoke(processHelper, args); - } catch(Exception e) { - if (e instanceof InvocationTargetException) { - InvocationTargetException ite = (InvocationTargetException) e; - if (ite.getTargetException() instanceof SyncException) { - throw (SyncException) ite.getTargetException(); + Object[] args = null; + Method method = null; + try { + method = processHelper.getClass().getDeclaredMethod(processName, new Class[]{String.class,Object[].class}); + } catch(NoSuchMethodException nsme) {} + + if (method != null) { + // Attempt to see if a method exists with parameters as an array. + args = new Object[2]; + args[0] = clientId; + args[1] = (queryArguments instanceof List ? ((List)queryArguments).toArray() : queryArguments); + } + else { + try { + method = processHelper.getClass().getDeclaredMethod(processName, new Class[]{String.class,Object.class}); + } catch(NoSuchMethodException nsme) {} + + if (method != null) { + args = new Object[2]; + args[0] = clientId; + args[1] = queryArguments; } else { - log.error("Unable to run Process", ite.getTargetException()); - throw new SyncException("Error Running Process", -101, "Unable to run process " + processName + ":\n" + ite.getTargetException().getMessage()); + args = new Object[1]; + args[0] = clientId; + // Don't catch the "NoSuchMethodException" here since we + // have tried the last method signature, now we just + // fail + method = processHelper.getClass().getDeclaredMethod(processName, new Class[]{String.class}); } } + result = method.invoke(processHelper, args); + } catch(InvocationTargetException e) { + if (e.getTargetException() instanceof SyncException) { + throw (SyncException) e.getTargetException(); + } else { - log.error("Unable to run Process", e); - throw new SyncException("Error Running Process", -101, "Unable to run process " + processName + ":\n" + e.getMessage()); + throw new SyncException("Error Running Process", -101, "Unable to run process " + processName + ":\n" + e.getTargetException().getMessage(), e); } + } catch(NoSuchMethodException e) { + throw new SyncException("Error Running Process", -101, "Unable to run process " + processName + ":\n" + e.getMessage(), e); + } catch(Exception e) { + throw new SyncException("Error Running Process", -101, "Unable to run process " + processName + ":\n" + e.getMessage(), e); } } @@ -415,7 +437,7 @@ public Object getChangeWatcherValue(ClassIDPair classIdPair, String fieldName, S Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); // Only ChangeWatcherValueHelper's have the "get" function. IChangeWatcherValueHelper cwh = (IChangeWatcherValueHelper) changeWatcherHelperFactory.getHelper(classIdPair.getClassName()); @@ -434,7 +456,7 @@ public Object findByExample(Object theQueryObject, List excludeProperties, String clientId) throws Exception { Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); if (theQueryObject instanceof IPerceroObject) { IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); @@ -442,7 +464,13 @@ 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, false); + List result = dataProvider.findByExample((IPerceroObject) theQueryObject, excludeProperties, userId, false); + + if (result != null && !result.isEmpty()) { + postGetHelper.postGetObject(result, userId, clientId); + } + + return result; } } @@ -455,7 +483,7 @@ public List systemFindByExample(Object theQueryObject, List systemFindByExample(Object theQueryObject, List excludeProperties, String clientId) throws Exception { Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); MappedClass mappedClass = mcm.getMappedClassByClassName(theQueryObject.getClass().getCanonicalName()); @@ -513,7 +541,7 @@ public Object searchByExample(Object theQueryObject, IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); List result = dataProvider.findByExample((IPerceroObject) theQueryObject, excludeProperties, userId, false); - if (result != null && result.size() > 0) { + if (result != null && !result.isEmpty()) { postGetHelper.postGetObject(result, userId, clientId); } @@ -531,7 +559,7 @@ public Object findById(ClassIDPair classIdPair, String clientId) throws Exceptio public Object findById(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); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); // Get the MappedClass and determine which DataProvider provides data for this object. IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); @@ -643,7 +671,7 @@ public List getHistory(ClassIDPair classIdPair, String clientI 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); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); // Get the MappedClass and determine which DataProvider provides data for this object. IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); @@ -666,7 +694,7 @@ public List findByIds(List classIdList, String cli Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); String userId = accessManager.getClientUserId(clientId); @@ -696,7 +724,7 @@ public ServerResponse putObject(IPerceroObject perceroObject, String transaction Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); // Get the MappedClass and determine which DataProvider provides data for this object. IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); @@ -744,82 +772,8 @@ public ServerResponse putObject(IPerceroObject perceroObject, String transaction IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); changedFields = dataProvider.getChangedMappedFields(perceroObject); if (changedFields == null || changedFields.size() > 0) { - // Something has changed. - result = dataProvider.putObject(perceroObject, changedFields, userId); - - if (result != null) { - // Now record the updated object. - ObjectModJournal newModJournal = new ObjectModJournal(); - newModJournal.setDateModified(updateDate); - newModJournal.setUserId(userId); - - if (transactionId == null || transactionId.length() == 0) - transactionId = UUID.randomUUID().toString(); - newModJournal.setTransactionId(transactionId); - newModJournal.setClassID(result.getID()); - newModJournal.setClassName(result.getClass().getName()); - - 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. - if (storeHistory && (result instanceof IHistoryObject)) - { - HistoricalObject historyObject = new HistoricalObject(); - historyObject.setObjectVersion(result.classVersion()); - historyObject.setID(UUID.randomUUID().toString()); - historyObject.setObjectChangeDate(updateDate); - historyObject.setObjectClassName(result.getClass().getName()); - historyObject.setObjectId(result.getID()); - historyObject.setObjectChangerId(userId); - historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); - - cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); - } - -// if (taskExecutor != null && false) { -// taskExecutor.execute(new PostPutTask(postPutHelper, BaseDataObject.toClassIdPair((BaseDataObject) result), userId, clientId, pushToClient, changedFields)); -// } else { - postPutHelper.postPutObject(BaseDataObject.toClassIdPair((BaseDataObject) result), userId, clientId, pushToClient, changedFields); -// } - - // For each changed field, we look at the reverse mapped - // relationship (if one exists) and update that object - // (this was already done in the cache by the - // cacheManager). - if (changedFields != null && !changedFields.isEmpty()) { - Iterator>> itrChangedFieldEntryset = changedFields.entrySet().iterator(); - while (itrChangedFieldEntryset.hasNext()) { - Map.Entry> nextEntry = itrChangedFieldEntryset.next(); - ClassIDPair thePair = nextEntry.getKey(); - Collection changedMappedFields = nextEntry.getValue(); - - // If thePair is NOT the object being updated, then need to run the postPutHelper for the Pair object as well. - if (!thePair.equals(classIdPair)) { - Map> thePairChangedFields = new HashMap>(1); - thePairChangedFields.put(thePair, changedMappedFields); - - // This will also run thePair through the ChangeWatcher check below. -// if (taskExecutor != null && false) { -// taskExecutor.execute(new PostPutTask(postPutHelper, thePair, userId, clientId, pushToClient, thePairChangedFields)); -// } else { - postPutHelper.postPutObject(thePair, userId, clientId, pushToClient, thePairChangedFields); -// } - } - else { - Iterator itrChangedFields = changedMappedFields.iterator(); - String[] fieldNames = new String[changedMappedFields.size()]; - int i = 0; - while (itrChangedFields.hasNext()) { - MappedField nextChangedField = itrChangedFields.next(); - fieldNames[i] = nextChangedField.getField().getName(); - i++; - } - accessManager.checkChangeWatchers(thePair, fieldNames, null, null); - } - } - } - } + result = handleUpdateObject_ChangedFields(perceroObject, transactionId, updateDate, clientId, + pushToClient, changedFields, dataProvider); } else { log.info("Unnecessary PutObject: " + perceroObject.getClass().getCanonicalName() + " (" + perceroObject.getID() + ")"); @@ -886,45 +840,8 @@ 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.putObject(perceroObject, changedFields, null); - - if (result != null) { - // Now record the updated object. - ObjectModJournal newModJournal = new ObjectModJournal(); - newModJournal.setID(UUID.randomUUID().toString()); - if (transactionId == null || transactionId.length() == 0) - transactionId = UUID.randomUUID().toString(); - newModJournal.setTransactionId(transactionId); - newModJournal.setClassID(result.getID()); - newModJournal.setClassName(result.getClass().getName()); - newModJournal.setDateModified(updateDate); - - 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. - if (storeHistory && (result instanceof IHistoryObject)) - { - HistoricalObject historyObject = new HistoricalObject(); - historyObject.setObjectVersion(result.classVersion()); - historyObject.setID(UUID.randomUUID().toString()); - historyObject.setObjectChangeDate(updateDate); - historyObject.setObjectClassName(result.getClass().getName()); - historyObject.setObjectId(result.getID()); - historyObject.setObjectChangerId(userId); - historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); - - cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); - - //syncSession.save(historyObject); - } - - if (taskExecutor != null && false) { - taskExecutor.execute(new PostPutTask(postPutHelper, BaseDataObject.toClassIdPair((BaseDataObject) result), userId, null, pushToUser, changedFields)); - } else { - postPutHelper.postPutObject(BaseDataObject.toClassIdPair((BaseDataObject) result), userId, null, pushToUser, changedFields); - } - } + result = handleUpdateObject_ChangedFields(perceroObject, transactionId, updateDate, userId, + pushToUser, changedFields, dataProvider); } else { log.info("Unnecessary PutObject: " + perceroObject.getClass().getCanonicalName() + " (" + perceroObject.getID() + ")"); @@ -939,6 +856,67 @@ public boolean systemPutObject(IPerceroObject perceroObject, String transactionI return (result != null); } + /** + * @param perceroObject + * @param transactionId + * @param updateDate + * @param userId + * @param pushToUser + * @param changedFields + * @param dataProvider + * @return + * @throws SyncException + * @throws IOException + * @throws JsonGenerationException + * @throws JsonMappingException + * @throws Exception + */ + private IPerceroObject handleUpdateObject_ChangedFields(IPerceroObject perceroObject, String transactionId, + Date updateDate, String clientId, boolean pushToClient, Map> changedFields, + IDataProvider dataProvider) + throws SyncException, IOException, JsonGenerationException, JsonMappingException, Exception { + IPerceroObject result; + + String userId = accessManager.getClientUserId(clientId); + result = dataProvider.putObject(perceroObject, changedFields, userId); + + if (result != null) { + // Now record the updated object. + ObjectModJournal newModJournal = new ObjectModJournal(); + newModJournal.setID(UUID.randomUUID().toString()); + if (transactionId == null || transactionId.length() == 0) + transactionId = UUID.randomUUID().toString(); + newModJournal.setTransactionId(transactionId); + newModJournal.setClassID(result.getID()); + newModJournal.setClassName(result.getClass().getName()); + newModJournal.setDateModified(updateDate); + + 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. + if (storeHistory && (result instanceof IHistoryObject)) { + HistoricalObject historyObject = new HistoricalObject(); + historyObject.setObjectVersion(result.classVersion()); + historyObject.setID(UUID.randomUUID().toString()); + historyObject.setObjectChangeDate(updateDate); + historyObject.setObjectClassName(result.getClass().getName()); + historyObject.setObjectId(result.getID()); + historyObject.setObjectChangerId(userId); + historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); + + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); + } + + if (taskExecutor != null && false) { + taskExecutor.execute(new PostPutTask(postPutHelper, BaseDataObject.toClassIdPair((BaseDataObject) result), userId, null, pushToClient, changedFields)); + } else { + postPutHelper.postPutObject(BaseDataObject.toClassIdPair((BaseDataObject) result), userId, null, pushToClient, changedFields); + } + } + return result; + } + public ServerResponse createObject(IPerceroObject perceroObject, String clientId) throws Exception { return createObject(perceroObject, clientId, false); } @@ -950,7 +928,7 @@ public ServerResponse createObject(IPerceroObject perceroObject, String clientId Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); if (perceroObject != null) { String userId = accessManager.getClientUserId(clientId); @@ -1125,7 +1103,7 @@ public ServerResponse deleteObject(ClassIDPair theClassIdPair, String clientId, Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); try { @@ -1139,13 +1117,7 @@ public ServerResponse deleteObject(ClassIDPair theClassIdPair, String clientId, hasAccess = dataProvider.getDeleteAccess(theClassIdPair, userId); if (hasAccess) { - IPerceroObject perceroObject = dataProvider.findById(theClassIdPair, null); - if (perceroObject == null) { - response.setIsSuccessful(true); - return response; - } - - if (systemDeleteObject(perceroObject, clientId, pushToClient, new HashSet())) { + if (systemDeleteObject(theClassIdPair, clientId, pushToClient)) { response.setIsSuccessful(true); } else { @@ -1164,164 +1136,266 @@ public ServerResponse deleteObject(ClassIDPair theClassIdPair, String clientId, return response; } - public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, boolean pushToUser) throws Exception { - return systemDeleteObject(perceroObject, clientId, pushToUser, new HashSet()); + public boolean systemDeleteObject(ClassIDPair classIdPair, String clientId, boolean pushToUser) throws Exception { + return systemDeleteObject(classIdPair, clientId, pushToUser, new HashSet()); } - public boolean systemDeleteObject(IPerceroObject perceroObject, String clientId, boolean pushToUser, Collection deletedObjects) throws Exception { - boolean result = true; - if(perceroObject == null) + + /** + * - The pushes out notifications to ALL related objects. + * - The DataProvider should handle the updated target objects by updating the cache (IFF they are in the cache) + * - The updated objects source objects are handled by the cascadeRemoveFieldReferences and nulledOnRemoveFieldReferences + * since these objects need to be deleted/updated in the data store as well. + * @param classIdPair + * @param clientId + * @param pushToUser + * @param deletedObjects + * @return + * @throws Exception + */ + public boolean systemDeleteObject(ClassIDPair classIdPair, String clientId, boolean pushToUser, + Collection deletedObjects) throws Exception { + + // Validate our input + if(classIdPair == null) return true; - if (deletedObjects.contains(perceroObject)) + if (deletedObjects.contains(classIdPair)) return true; else - deletedObjects.add(perceroObject); + deletedObjects.add(classIdPair); String userId = accessManager.getClientUserId(clientId); IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(perceroObject.getClass().getName()); - if (mappedClass != null) { - IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - - perceroObject = (IPerceroObject) dataProvider.findById(new ClassIDPair(perceroObject.getID(), perceroObject.getClass().getCanonicalName()), null); + MappedClass mappedClass = mcm.getMappedClassByClassName(classIdPair.getClassName()); + if (mappedClass == null) { + return false; + } + + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); + + IPerceroObject perceroObject = (IPerceroObject) dataProvider.findById(classIdPair, null); + + if (perceroObject == null) { + return true; + } + + handleDeleteObject_CascadeRemove(perceroObject, mappedClass, deletedObjects, clientId); + + handleDeleteObject_CascadeNull(perceroObject, mappedClass, clientId); + + // This is a list of objects that need to be notified that they have + // somehow changed. That somehow is directly linked to these objects + // relationship with the deleted object. + + if (dataProvider.deleteObject(BaseDataObject.toClassIdPair(perceroObject), userId)) { + // Also store historical record, if necessary. + if (storeHistory && (perceroObject instanceof IHistoryObject)) + { + try { + HistoricalObject historyObject = new HistoricalObject(); + historyObject.setObjectVersion(perceroObject.classVersion()); + historyObject.setID(UUID.randomUUID().toString()); + historyObject.setObjectChangeDate(new Date()); + historyObject.setObjectClassName(perceroObject.getClass().getName()); + historyObject.setObjectId(perceroObject.getID()); + historyObject.setObjectChangerId(userId); + historyObject.setObjectData(safeObjectMapper.writeValueAsString(perceroObject)); + + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(perceroObject.getClass().getCanonicalName(), perceroObject.getID()), historyObject); + } catch(Exception e) { + log.warn("Unable to save HistoricalObject in deleteObject", e); + } + } - if (perceroObject == null) { - return true; + if (taskExecutor != null && false) { + taskExecutor.execute(new PostDeleteTask(postDeleteHelper, perceroObject, userId, clientId, pushToUser)); + } else { + postDeleteHelper.postDeleteObject(perceroObject, userId, clientId, pushToUser); } + + return true; + } - Iterator> itrCascadeRemoveFieldReferencesEntrySet = mappedClass.cascadeRemoveFieldReferences.entrySet().iterator(); - while (itrCascadeRemoveFieldReferencesEntrySet.hasNext()) { - Map.Entry nextEntry = itrCascadeRemoveFieldReferencesEntrySet.next(); - MappedField nextRemoveMappedFieldRef = nextEntry.getKey(); - try { - MappedField nextMappedField = nextEntry.getValue(); - 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()) { - IPerceroObject nextReferencingObject = itrReferencingObjects.next(); - systemDeleteObject(nextReferencingObject, clientId, true, deletedObjects); + return false; + } + + /** + * Given the perceroObject, goes through each relationship where the related + * object relationship must be set to NULL before perceroObject can be + * removed -> cascade update. + * + * @param perceroObject + * @param mappedClass + * @param userId + * @throws SyncDataException + */ + private void handleDeleteObject_CascadeNull(IPerceroObject perceroObject, MappedClass mappedClass, String clientId) + throws SyncDataException { + Iterator> itrNulledOnRemoveFieldReferencesEntrySet = mappedClass.getNulledOnRemoveFieldReferences().entrySet().iterator(); + while (itrNulledOnRemoveFieldReferencesEntrySet.hasNext()) { + Map.Entry nextEntry = itrNulledOnRemoveFieldReferencesEntrySet.next(); + MappedField nextToNullMappedFieldRef = nextEntry.getKey(); + try { + MappedField nextMappedField = nextEntry.getValue(); + if (nextMappedField == null) { + // There is no direct link from mappedClass, so need to get all by example. + IPerceroObject tempObject = (IPerceroObject) nextToNullMappedFieldRef.getMappedClass().newPerceroObject(); + nextToNullMappedFieldRef.getSetter().invoke(tempObject, perceroObject); + IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextToNullMappedFieldRef.getMappedClass().dataProviderName); + List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); + Iterator itrReferencingObjects = referencingObjects.iterator(); + while (itrReferencingObjects.hasNext()) { + IPerceroObject nextReferencingObject = itrReferencingObjects.next(); + nextToNullMappedFieldRef.setToNull(nextReferencingObject); +// systemPutObject((IPerceroObject) nextReferencingObject, null, new Date(), userId, true); +// +// TODO: Is this better? + Map> changedFields = new HashMap>(1); + Collection mappedFields = new ArrayList(1); + mappedFields.add(nextToNullMappedFieldRef); + changedFields.put(BaseDataObject.toClassIdPair(nextReferencingObject), mappedFields); + handleUpdateObject_ChangedFields((IPerceroObject) nextReferencingObject, null, new Date(), clientId, true, changedFields, dataProviderManager.getDataProviderByName(nextToNullMappedFieldRef.getMappedClass().dataProviderName)); + } + } + else { + // Since perceroObject is fully loaded, we have the list hanging off of perceroObject + if (nextMappedField instanceof MappedFieldList) { + List referencingObjects = (List) nextMappedField.getGetter().invoke(perceroObject); + if (referencingObjects != null && !referencingObjects.isEmpty()) { + for(IPerceroObject nextReferencingObject : referencingObjects) { + nextReferencingObject = systemGetByObject(nextReferencingObject); + nextToNullMappedFieldRef.setToNull(nextReferencingObject); +// systemPutObject((IPerceroObject) nextReferencingObject, null, new Date(), userId, true); + Map> changedFields = new HashMap>(1); + Collection mappedFields = new ArrayList(1); + mappedFields.add(nextToNullMappedFieldRef); + changedFields.put(BaseDataObject.toClassIdPair(nextReferencingObject), mappedFields); + handleUpdateObject_ChangedFields((IPerceroObject) nextReferencingObject, null, new Date(), clientId, true, changedFields, dataProviderManager.getDataProviderByName(nextToNullMappedFieldRef.getMappedClass().dataProviderName)); + } + + // Now remove these objects from teh list. + referencingObjects.clear(); + } + } + else if (nextMappedField instanceof MappedFieldPerceroObject) { + IPerceroObject referencingObject = (IPerceroObject) nextMappedField.getGetter().invoke(perceroObject); + if (referencingObject != null) { + referencingObject = systemGetByObject(referencingObject); + nextToNullMappedFieldRef.setToNull(referencingObject); +// systemPutObject((IPerceroObject) referencingObject, null, new Date(), userId, true); + Map> changedFields = new HashMap>(1); + Collection mappedFields = new ArrayList(1); + mappedFields.add(nextToNullMappedFieldRef); + changedFields.put(BaseDataObject.toClassIdPair(referencingObject), mappedFields); + handleUpdateObject_ChangedFields((IPerceroObject) referencingObject, null, new Date(), clientId, true, changedFields, dataProviderManager.getDataProviderByName(nextToNullMappedFieldRef.getMappedClass().dataProviderName)); + + // Now remove the reference to this object. + nextMappedField.setToNull(perceroObject); } } else { - // We have the reverse lookup right here. - 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); + // Fall back case if we don't have a special way of handling this type of MappedField + IPerceroObject tempObject = (IPerceroObject) nextToNullMappedFieldRef.getMappedClass().clazz.newInstance(); + nextToNullMappedFieldRef.getSetter().invoke(tempObject, perceroObject); + IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextToNullMappedFieldRef.getMappedClass().dataProviderName); List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); Iterator itrReferencingObjects = referencingObjects.iterator(); while (itrReferencingObjects.hasNext()) { IPerceroObject nextReferencingObject = itrReferencingObjects.next(); - systemDeleteObject(nextReferencingObject, clientId, true, deletedObjects); + nextToNullMappedFieldRef.setToNull(nextReferencingObject); +// systemPutObject((IPerceroObject) nextReferencingObject, null, new Date(), userId, true); + Map> changedFields = new HashMap>(1); + Collection mappedFields = new ArrayList(1); + mappedFields.add(nextToNullMappedFieldRef); + changedFields.put(BaseDataObject.toClassIdPair(nextReferencingObject), mappedFields); + handleUpdateObject_ChangedFields((IPerceroObject) nextReferencingObject, null, new Date(), clientId, true, changedFields, dataProviderManager.getDataProviderByName(nextToNullMappedFieldRef.getMappedClass().dataProviderName)); } } - } catch(Exception e) { - log.error("Unable to remove referenced object", e); - result = false; } + } catch(Exception e) { + throw new SyncDataException(SyncDataException.DELETE_OBJECT_ERROR, SyncDataException.DELETE_OBJECT_ERROR_CODE, e); } + } + } - Object[] nullObject = new Object[1]; - nullObject[0] = null; - Iterator> itrNulledOnRemoveFieldReferencesEntrySet = mappedClass.nulledOnRemoveFieldReferences.entrySet().iterator(); - while (itrNulledOnRemoveFieldReferencesEntrySet.hasNext()) { - Map.Entry nextEntry = itrNulledOnRemoveFieldReferencesEntrySet.next(); - MappedField nextToNullMappedFieldRef = nextEntry.getKey(); - try { - MappedField nextMappedField = nextEntry.getValue(); - 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()) { - IPerceroObject nextReferencingObject = itrReferencingObjects.next(); - nextToNullMappedFieldRef.getSetter().invoke(nextReferencingObject, nullObject); - systemPutObject((IPerceroObject) nextReferencingObject, null, new Date(), userId, true); + /** + * Given the perceroObject, goes through each relationship where the related + * object must be removed before perceroObject can be removed -> cascade + * remove. + * + * @param perceroObject + * @param mappedClass + * @param deletedObjects + * @param clientId + */ + private void handleDeleteObject_CascadeRemove(IPerceroObject perceroObject, + MappedClass mappedClass, + Collection deletedObjects, + String clientId) throws SyncDataException { + + Iterator> itrCascadeRemoveFieldReferencesEntrySet = mappedClass.getCascadeRemoveFieldReferences().entrySet().iterator(); + while (itrCascadeRemoveFieldReferencesEntrySet.hasNext()) { + Map.Entry nextEntry = itrCascadeRemoveFieldReferencesEntrySet.next(); + MappedField nextRemoveMappedFieldRef = nextEntry.getKey(); + try { + MappedField nextMappedField = nextEntry.getValue(); + if (nextMappedField == null) { + // There is no direct link from mappedClass, so need to get all by example. + IPerceroObject tempObject = (IPerceroObject) nextRemoveMappedFieldRef.getMappedClass().newPerceroObject(); + nextRemoveMappedFieldRef.getSetter().invoke(tempObject, perceroObject); + IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextRemoveMappedFieldRef.getMappedClass().dataProviderName); + List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); + Iterator itrReferencingObjects = referencingObjects.iterator(); + while (itrReferencingObjects.hasNext()) { + IPerceroObject nextReferencingObject = itrReferencingObjects.next(); + systemDeleteObject(BaseDataObject.toClassIdPair(nextReferencingObject), clientId, true, deletedObjects); + } + } + else { + // Since perceroObject is fully loaded, we have the list hanging off of perceroObject + if (nextMappedField instanceof MappedFieldList) { + List referencingObjects = (List) nextMappedField.getGetter().invoke(perceroObject); + if (referencingObjects != null && !referencingObjects.isEmpty()) { + for(IPerceroObject nextReferencingObject : referencingObjects) { + systemDeleteObject(BaseDataObject.toClassIdPair(nextReferencingObject), clientId, true, deletedObjects); + } + + // Now remove these objects from the list. + referencingObjects.clear(); + } + } + else if (nextMappedField instanceof MappedFieldPerceroObject) { + IPerceroObject referencingObject = (IPerceroObject) nextMappedField.getGetter().invoke(perceroObject); + if (referencingObject != null) { + systemDeleteObject(BaseDataObject.toClassIdPair(referencingObject), clientId, true, deletedObjects); + + // Now remove the refernce to this object. + nextMappedField.setToNull(perceroObject); } } else { - // We have the reverse lookup right here. - 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); + // Fall back case if we don't have a special way of handling this type of MappedField + IPerceroObject tempObject = (IPerceroObject) nextRemoveMappedFieldRef.getMappedClass().clazz.newInstance(); + nextRemoveMappedFieldRef.getSetter().invoke(tempObject, perceroObject); + IDataProvider dataProviderRef = dataProviderManager.getDataProviderByName(nextRemoveMappedFieldRef.getMappedClass().dataProviderName); List referencingObjects = dataProviderRef.findByExample(tempObject, null, null, false); Iterator itrReferencingObjects = referencingObjects.iterator(); while (itrReferencingObjects.hasNext()) { IPerceroObject nextReferencingObject = itrReferencingObjects.next(); - nextToNullMappedFieldRef.getSetter().invoke(nextReferencingObject, nullObject); - systemPutObject((IPerceroObject) nextReferencingObject, null, new Date(), userId, true); + systemDeleteObject(BaseDataObject.toClassIdPair(nextReferencingObject), clientId, true, deletedObjects); } } - } catch(Exception e) { - log.error("Unable to remove referenced object", e); - result = false; - } - } - - 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)) { - // Also store historical record, if necessary. - if (storeHistory && (perceroObject instanceof IHistoryObject)) - { - try { - HistoricalObject historyObject = new HistoricalObject(); - historyObject.setObjectVersion(perceroObject.classVersion()); - historyObject.setID(UUID.randomUUID().toString()); - historyObject.setObjectChangeDate(new Date()); - historyObject.setObjectClassName(perceroObject.getClass().getName()); - historyObject.setObjectId(perceroObject.getID()); - historyObject.setObjectChangerId(userId); - historyObject.setObjectData(safeObjectMapper.writeValueAsString(perceroObject)); - - cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(perceroObject.getClass().getCanonicalName(), perceroObject.getID()), historyObject); - } catch(Exception e) { - log.warn("Unable to save HistoricalObject in deleteObject", e); - } - } - - if (taskExecutor != null && false) { - taskExecutor.execute(new PostDeleteTask(postDeleteHelper, perceroObject, userId, clientId, pushToUser)); - } else { - 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 { - result = false; + } catch(Exception e) { + throw new SyncDataException(SyncDataException.DELETE_OBJECT_ERROR, SyncDataException.DELETE_OBJECT_ERROR_CODE, e); } } - - return result; } public void updatesReceived(ClassIDPair[] theObjects, String clientId) throws Exception { Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); // Remove UpdateJournals for this client. accessManager.deleteUpdateJournals(clientId, theObjects); @@ -1330,7 +1404,7 @@ public void updatesReceived(ClassIDPair[] theObjects, String clientId) throws Ex public void deletesReceived(ClassIDPair[] theObjects, String clientId) throws Exception { Boolean isValidClient = accessManager.validateClientByClientId(clientId); if (!isValidClient) - throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE); + throw new ClientException(ClientException.INVALID_CLIENT, ClientException.INVALID_CLIENT_CODE, "", clientId); // Remove DeleteJournals for this client. accessManager.deleteDeleteJournals(clientId, theObjects); @@ -1361,7 +1435,7 @@ public Boolean pushClientUpdateJournals(String clientId, Collection list try { // Optimization: create the JSON string of the object. String userId = accessManager.getClientUserId(clientId); - String objectJson = ""; + StringBuilder objectJson = new StringBuilder(); int counter = 0; PushUpdateResponse pushUpdateResponse = null; @@ -1392,8 +1466,8 @@ public Boolean pushClientUpdateJournals(String clientId, Collection list pushUpdateResponse.getObjectList().add((BaseDataObject) anObject); if (anObject instanceof IPerceroObject) { if (counter> 0) - objectJson += ","; - objectJson += ((BaseDataObject)anObject).toJson(); + objectJson.append(','); + objectJson.append(((BaseDataObject)anObject).toJson()); counter++; } } @@ -1401,7 +1475,7 @@ public Boolean pushClientUpdateJournals(String clientId, Collection list if (pushUpdateResponse != null && counter > 0) { //pushObjectToRabbit(pushUpdateResponse, clientId); - pushUpdateResponse.setObjectJson(objectJson); + pushUpdateResponse.setObjectJson(objectJson.toString()); pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, clientId); //pushSyncHelper.pushJsonToRouting(pushUpdateResponse.toJson(objectJson, safeObjectMapper), PushUpdateResponse.class, clientId); } @@ -1426,7 +1500,7 @@ public Boolean pushClientDeleteJournals(String clientId, Collection list if (listDeleteJournals.size() > 0) { try { // Optimization: create the JSON string of the object. - String objectJson = ""; + StringBuilder objectJson = new StringBuilder(); int counter = 0; PushDeleteResponse pushDeleteResponse = null; @@ -1455,15 +1529,15 @@ public Boolean pushClientDeleteJournals(String clientId, Collection list if (classIdPair != null) { pushDeleteResponse.getObjectList().add(classIdPair); if (counter> 0) - objectJson += ","; - objectJson += classIdPair.toJson(); + objectJson.append(','); + objectJson.append(classIdPair.toJson()); counter++; } } if (pushDeleteResponse != null) { //pushObjectToRabbit(pushDeleteResponse, clientId); - pushDeleteResponse.setObjectJson(objectJson); + pushDeleteResponse.setObjectJson(objectJson.toString()); pushSyncHelper.pushSyncResponseToClient(pushDeleteResponse, clientId); //pushSyncHelper.pushJsonToRouting(pushDeleteResponse.toJson(objectJson, safeObjectMapper), PushDeleteResponse.class, clientId); } diff --git a/src/main/java/com/percero/agents/sync/vo/BaseDataObject.java b/src/main/java/com/percero/agents/sync/vo/BaseDataObject.java index a641f1f..2825e85 100644 --- a/src/main/java/com/percero/agents/sync/vo/BaseDataObject.java +++ b/src/main/java/com/percero/agents/sync/vo/BaseDataObject.java @@ -12,10 +12,8 @@ import javax.persistence.Transient; import org.apache.log4j.Logger; -import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.map.ObjectMapper; -import org.mortbay.log.Log; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -25,7 +23,6 @@ import com.percero.agents.sync.manager.DataExternalizer; import com.percero.agents.sync.metadata.MappedClass; import com.percero.agents.sync.metadata.MappedClass.MappedClassMethodPair; -import com.percero.agents.sync.services.SyncAgentService; import com.percero.framework.vo.IPerceroObject; import com.percero.serial.JsonUtils; @@ -92,10 +89,14 @@ public String toJson(ObjectMapper objectMapper) { } public String toJson(Boolean encloseString, ObjectMapper objectMapper) { - String objectJson = retrieveJson(objectMapper); - if (encloseString) - objectJson = "{" + objectJson + "}"; - return objectJson; + StringBuilder objectJson; + if (encloseString) { + objectJson = new StringBuilder("{").append(retrieveJson(objectMapper)).append('}'); + } + else { + objectJson = new StringBuilder(retrieveJson(objectMapper)); + } + return objectJson.toString(); } public String retrieveJson(ObjectMapper objectMapper) { @@ -107,25 +108,27 @@ public String toEmbeddedJson() { } public String toEmbeddedJson(Boolean encloseString) { - String objectJson = retrieveEmbeddedJson(); - if (encloseString) - objectJson = "{" + objectJson + "}"; - return objectJson; + StringBuilder objectJson; + if (encloseString) { + objectJson = new StringBuilder("{").append("\"className\":\"").append(getClass().getCanonicalName()).append("\",").append("\"ID\":\"").append(getID()).append("\"").append('}'); + } + else { + objectJson = new StringBuilder("\"className\":\"").append(getClass().getCanonicalName()).append("\",").append("\"ID\":\"").append(getID()).append("\""); + } + return objectJson.toString(); } public String retrieveBaseJson() { - String objectJson = "\"cn\":\"" + getClass().getCanonicalName() + "\"," + - "\"ID\":\"" + getID() + "\""; + StringBuilder objectJson = new StringBuilder("\"cn\":\"").append(getClass().getCanonicalName()).append("\",").append("\"ID\":\"").append(getID()).append("\""); //+ "\"dataSource\":\"" + getDataSource() + "\"" ; - return objectJson; + return objectJson.toString(); } public String retrieveEmbeddedJson() { - String objectJson = "\"className\":\"" + getClass().getCanonicalName() + "\"," + - "\"ID\":\"" + getID() + "\""; + StringBuilder objectJson = new StringBuilder("\"className\":\"").append(getClass().getCanonicalName()).append("\",").append("\"ID\":\"").append(getID()).append("\""); - return objectJson; + return objectJson.toString(); } public void fromJson(String jsonString) { diff --git a/src/main/java/com/percero/agents/sync/vo/FindByIdResponse.java b/src/main/java/com/percero/agents/sync/vo/FindByIdResponse.java index f9ffeff..546204a 100644 --- a/src/main/java/com/percero/agents/sync/vo/FindByIdResponse.java +++ b/src/main/java/com/percero/agents/sync/vo/FindByIdResponse.java @@ -16,8 +16,7 @@ public void setResult(BaseDataObject result) { @Override public String retrieveBaseJson(ObjectMapper objectMapper) { - String objectJson = super.retrieveBaseJson(objectMapper) + ","; - objectJson += "\"result\":" + (getResult() == null ? "null" : getResult().toJson(objectMapper)); + String objectJson = super.retrieveBaseJson(objectMapper) + ",\"result\":" + (getResult() == null ? "null" : getResult().toJson(objectMapper)); return objectJson; } } diff --git a/src/main/java/com/percero/agents/sync/vo/FindByIdsResponse.java b/src/main/java/com/percero/agents/sync/vo/FindByIdsResponse.java index 91c11a1..9b31c70 100644 --- a/src/main/java/com/percero/agents/sync/vo/FindByIdsResponse.java +++ b/src/main/java/com/percero/agents/sync/vo/FindByIdsResponse.java @@ -17,15 +17,15 @@ public void setResult(List result) { @Override public String retrieveBaseJson(ObjectMapper objectMapper) { - String objectJson = super.retrieveBaseJson(objectMapper) + ",\"result\":["; + StringBuilder objectJson = new StringBuilder(super.retrieveBaseJson(objectMapper) + ",\"result\":["); int counter = 0; for(BaseDataObject nextBDO : getResult()) { if (counter > 0) - objectJson += ","; - objectJson += nextBDO.toJson(objectMapper); + objectJson.append(','); + objectJson.append(nextBDO.toJson(objectMapper)); counter++; } - objectJson += "]"; - return objectJson; + objectJson.append(']'); + return objectJson.toString(); } } diff --git a/src/main/java/com/percero/agents/sync/vo/PushCWUpdateResponse.java b/src/main/java/com/percero/agents/sync/vo/PushCWUpdateResponse.java index 981d5a1..f6ee78c 100644 --- a/src/main/java/com/percero/agents/sync/vo/PushCWUpdateResponse.java +++ b/src/main/java/com/percero/agents/sync/vo/PushCWUpdateResponse.java @@ -45,128 +45,128 @@ public void setValue(Object value) { @SuppressWarnings("rawtypes") public String toJson(ObjectMapper objectMapper) { - String objectJson = "{" + super.retrieveJson(objectMapper) + ",\"classIdPair\":"; + StringBuilder objectJson = new StringBuilder("{").append(super.retrieveJson(objectMapper)).append(",\"classIdPair\":"); if (getClassIdPair() != null) { - objectJson += getClassIdPair().toEmbeddedJson(); + objectJson.append(getClassIdPair().toEmbeddedJson()); } else { - objectJson += "null"; + objectJson.append("null"); } - objectJson += ",\"fieldName\":"; + objectJson.append(",\"fieldName\":"); if (getFieldName() == null) - objectJson += "null"; + objectJson.append("null"); else { if (objectMapper == null) objectMapper = new ObjectMapper(); try { - objectJson += objectMapper.writeValueAsString(getFieldName()); + objectJson.append(objectMapper.writeValueAsString(getFieldName())); } catch (JsonGenerationException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } catch (JsonMappingException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } catch (IOException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } } - objectJson += ",\"params\":"; + objectJson.append(",\"params\":"); if (getParams() == null) - objectJson += "null"; + objectJson.append("null"); else { - objectJson += "["; + objectJson.append('['); if (objectMapper == null) objectMapper = new ObjectMapper(); int paramsCounter = 0; for(String nextParam : getParams()) { try { if (paramsCounter > 0) - objectJson += ","; - objectJson += objectMapper.writeValueAsString(nextParam); + objectJson.append(','); + objectJson.append(objectMapper.writeValueAsString(nextParam)); paramsCounter++; } catch (JsonGenerationException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } catch (JsonMappingException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } catch (IOException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } } - objectJson += "]"; + objectJson.append(']'); } - objectJson += ",\"value\":"; + objectJson.append(",\"value\":"); if (value == null) { - objectJson += "null"; + objectJson.append("null"); } else { if (getValue() instanceof BaseDataObject) { - objectJson += ((BaseDataObject) getValue()).toEmbeddedJson(); + objectJson.append(((BaseDataObject) getValue()).toEmbeddedJson()); } else if (getValue() instanceof Collection) { Collection collection = (Collection) getValue(); if (objectMapper == null) objectMapper = new ObjectMapper(); - objectJson += "["; + objectJson.append('['); int collectionCounter = 0; for(Object nextCollectionObject : collection) { if (collectionCounter > 0) - objectJson += ","; + objectJson.append(','); if (nextCollectionObject instanceof BaseDataObject) { - objectJson += ((BaseDataObject) nextCollectionObject).toEmbeddedJson(); + objectJson.append(((BaseDataObject) nextCollectionObject).toEmbeddedJson()); } else { try { - objectJson += objectMapper.writeValueAsString(nextCollectionObject); + objectJson.append(objectMapper.writeValueAsString(nextCollectionObject)); } catch (JsonGenerationException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } catch (JsonMappingException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } catch (IOException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } } collectionCounter++; } - objectJson += "]"; + objectJson.append(']'); } else { if (getValue() == null) - objectJson += "null"; + objectJson.append("null"); else { if (objectMapper == null) objectMapper = new ObjectMapper(); try { - objectJson += objectMapper.writeValueAsString(getValue()); + objectJson.append(objectMapper.writeValueAsString(getValue())); } catch (JsonGenerationException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } catch (JsonMappingException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } catch (IOException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } } } } - objectJson += "}"; + objectJson.append('}'); - return objectJson; + return objectJson.toString(); } } diff --git a/src/main/java/com/percero/agents/sync/vo/PushDeleteResponse.java b/src/main/java/com/percero/agents/sync/vo/PushDeleteResponse.java index aaf6ae9..bf555ca 100644 --- a/src/main/java/com/percero/agents/sync/vo/PushDeleteResponse.java +++ b/src/main/java/com/percero/agents/sync/vo/PushDeleteResponse.java @@ -18,15 +18,15 @@ public void setObjectList(List value) { public String toJson(ObjectMapper objectMapper) { if (objectJson == null) { - String objectListJson = ""; + StringBuilder objectListJson = new StringBuilder(); int objectCounter = 0; for(RemovedClassIDPair nextObject : getObjectList()) { if (objectCounter > 0) - objectListJson += ","; - objectListJson += nextObject.toEmbeddedJson(); + objectListJson.append(','); + objectListJson.append(nextObject.toEmbeddedJson()); objectCounter++; } - return toJson(objectListJson, objectMapper); + return toJson(objectListJson.toString(), objectMapper); } else { return toJson(objectJson, objectMapper); @@ -39,8 +39,7 @@ public void setObjectJson(String value) { } public String toJson(String objectListJson, ObjectMapper objectMapper) { - String objectJson = "{" + super.retrieveJson(objectMapper) + ",\"objectList\":["; - objectJson += objectListJson + "]}"; + String objectJson = "{" + super.retrieveJson(objectMapper) + ",\"objectList\":[" + objectListJson + "]}"; return objectJson; } } diff --git a/src/main/java/com/percero/agents/sync/vo/PushObjectUpdate.java b/src/main/java/com/percero/agents/sync/vo/PushObjectUpdate.java index 4f4667c..a2a105a 100644 --- a/src/main/java/com/percero/agents/sync/vo/PushObjectUpdate.java +++ b/src/main/java/com/percero/agents/sync/vo/PushObjectUpdate.java @@ -22,31 +22,31 @@ public void setResult(BaseDataObject result) { @Override public String retrieveBaseJson(ObjectMapper objectMapper) { - String objectJson = super.retrieveBaseJson(objectMapper) + ","; - objectJson += "\"result\":" + (getResult() == null ? "null" : getResult().toJson(objectMapper)); + StringBuilder objectJson = new StringBuilder(super.retrieveBaseJson(objectMapper)).append(',') + .append("\"result\":").append((getResult() == null ? "null" : getResult().toJson(objectMapper))); - objectJson += ",\"fieldNames\":["; + objectJson.append(",\"fieldNames\":["); if (getFieldNames() != null && getFieldNames().length > 0) { if (objectMapper == null) objectMapper = new ObjectMapper(); for(int i=0; i < getFieldNames().length; i++) { try { - objectJson += objectMapper.writeValueAsString(getFieldNames()[i]); + objectJson.append(objectMapper.writeValueAsString(getFieldNames()[i])); } catch (JsonGenerationException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } catch (JsonMappingException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } catch (IOException e) { - objectJson += "null"; + objectJson.append("null"); e.printStackTrace(); } } } - objectJson += "]"; + objectJson.append(']'); - return objectJson; + return objectJson.toString(); } private String[] fieldNames; diff --git a/src/main/java/com/percero/agents/sync/vo/PushUpdateResponse.java b/src/main/java/com/percero/agents/sync/vo/PushUpdateResponse.java index e7025e6..bea0746 100644 --- a/src/main/java/com/percero/agents/sync/vo/PushUpdateResponse.java +++ b/src/main/java/com/percero/agents/sync/vo/PushUpdateResponse.java @@ -37,15 +37,15 @@ public void addUpdatedField(String fieldName) { public String toJson(ObjectMapper objectMapper) { if (objectJson == null) { - String objectListJson = ""; + StringBuilder objectListJson = new StringBuilder(); int objectCounter = 0; for(BaseDataObject nextObject : getObjectList()) { if (objectCounter > 0) - objectListJson += ","; - objectListJson += nextObject.toJson(); + objectListJson.append(','); + objectListJson.append(nextObject.toJson()); objectCounter++; } - return toJson(objectListJson, objectMapper); + return toJson(objectListJson.toString(), objectMapper); } else { return toJson(objectJson, objectMapper); @@ -61,8 +61,8 @@ protected String getObjectJson() { } public String toJson(String objectListJson, ObjectMapper objectMapper) { - String objectJson = "{" + super.retrieveJson(objectMapper) + ",\"objectList\":["; - objectJson += objectListJson + "],\"updatedFields\":["; + StringBuilder objectJson = new StringBuilder("{").append(super.retrieveJson(objectMapper)).append(",\"objectList\":[") + .append(objectListJson).append("],\"updatedFields\":["); int partialsCounter = 0; if (getUpdatedFields() != null) { @@ -70,19 +70,19 @@ public String toJson(String objectListJson, ObjectMapper objectMapper) { while (itrUpdatedFields.hasNext()) { String nextField = itrUpdatedFields.next(); if (partialsCounter > 0) - objectJson += ","; - objectJson += "\"" + nextField + "\""; // Because this is a field name we shouldn't need any special string transforms. + objectJson.append(','); + objectJson.append('"').append(nextField).append('"'); // Because this is a field name we shouldn't need any special string transforms. partialsCounter++; } } else { - objectJson += "null"; + objectJson.append("null"); } - objectJson += "]"; + objectJson.append(']'); - objectJson += "}"; - return objectJson; + objectJson.append('}'); + return objectJson.toString(); } } diff --git a/src/main/java/com/percero/agents/sync/vo/SearchByExampleResponse.java b/src/main/java/com/percero/agents/sync/vo/SearchByExampleResponse.java index 0308726..7b1a876 100644 --- a/src/main/java/com/percero/agents/sync/vo/SearchByExampleResponse.java +++ b/src/main/java/com/percero/agents/sync/vo/SearchByExampleResponse.java @@ -17,15 +17,15 @@ public void setResult(List result) { @Override public String retrieveBaseJson(ObjectMapper objectMapper) { - String objectJson = super.retrieveBaseJson(objectMapper) + ",\"result\":["; + StringBuilder objectJson = new StringBuilder(super.retrieveBaseJson(objectMapper)).append(",\"result\":["); int counter = 0; for(BaseDataObject nextBDO : result) { if (counter > 0) - objectJson += ","; - objectJson += nextBDO.toJson(objectMapper); + objectJson.append(','); + objectJson.append(nextBDO.toJson(objectMapper)); counter++; } - objectJson += "]"; - return objectJson; + objectJson.append(']'); + return objectJson.toString(); } } diff --git a/src/main/java/com/percero/agents/sync/vo/SyncResponse.java b/src/main/java/com/percero/agents/sync/vo/SyncResponse.java index 742f2ef..1967077 100644 --- a/src/main/java/com/percero/agents/sync/vo/SyncResponse.java +++ b/src/main/java/com/percero/agents/sync/vo/SyncResponse.java @@ -100,47 +100,69 @@ public String retrieveJson(ObjectMapper objectMapper) { } public String retrieveBaseJson(ObjectMapper objectMapper) { - String objectJson = "\"cn\":\"" + getClass().getCanonicalName() + "\"," + - "\"clientId\":" + (getClientId() == null ? "null" : "\"" + getClientId() + "\"") + "," + - "\"timestamp\":" + getTimestamp().toString() + ","; + StringBuilder objectJson = new StringBuilder("\"cn\":\"").append(getClass().getCanonicalName()).append("\",") + .append("\"clientId\":"); + + if (getClientId() == null) { + objectJson.append("null"); + } + else { + objectJson.append('"').append(getClientId()).append('"'); + } + + objectJson.append(',').append("\"timestamp\":").append(getTimestamp().toString()).append(','); if (getIds() != null) { - objectJson += "\"ids\":["; + objectJson.append("\"ids\":["); int idsCounter = 0; for(String nextId : getIds()) { if (idsCounter > 0) - objectJson += ","; - objectJson += "\"" + nextId + "\""; + objectJson.append(','); + objectJson.append('"').append(nextId).append('"'); idsCounter++; } - objectJson += "],"; + objectJson.append("],"); } else { - objectJson += "\"ids\":null,"; + objectJson.append("\"ids\":null,"); } try { if (objectMapper == null) objectMapper = new ObjectMapper(); - objectJson += "\"data\":" + (getData() == null ? "null" : objectMapper.writeValueAsString(getData())) + ","; + objectJson.append("\"data\":").append((getData() == null ? "null" : objectMapper.writeValueAsString(getData()))).append(','); } catch (JsonGenerationException e) { // TODO Auto-generated catch block e.printStackTrace(); - objectJson += "\"data\":null"; + objectJson.append("\"data\":null"); } catch (JsonMappingException e) { // TODO Auto-generated catch block e.printStackTrace(); - objectJson += "\"data\":null"; + objectJson.append("\"data\":null"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); - objectJson += "\"data\":null"; + objectJson.append("\"data\":null"); } - objectJson += "\"type\":" + (getType() == null ? "null" : "\"" + getType() + "\"") + "," + - "\"correspondingMessageId\":" + (getCorrespondingMessageId() == null ? "null" : "\"" + getCorrespondingMessageId() + "\"") + "," + - "\"gatewayMessageId\":" + (getGatewayMessageId() == null ? "null" : "\"" + getGatewayMessageId() + "\""); + objectJson.append("\"type\":").append((getType() == null ? "null" : "\"" + getType() + "\"")).append(',') + .append("\"correspondingMessageId\":"); - return objectJson; + if (getCorrespondingMessageId() == null) { + objectJson.append("null"); + } + else { + objectJson.append('"').append(getCorrespondingMessageId()).append('"'); + } + objectJson.append(',').append("\"gatewayMessageId\":"); + + if (getGatewayMessageId() == null) { + objectJson.append("null"); + } + else { + objectJson.append('"').append(getGatewayMessageId()).append('"'); + } + + return objectJson.toString(); } } diff --git a/src/main/java/com/percero/amqp/PerceroAgentListener.java b/src/main/java/com/percero/amqp/PerceroAgentListener.java index a5f2122..1503ae1 100644 --- a/src/main/java/com/percero/amqp/PerceroAgentListener.java +++ b/src/main/java/com/percero/amqp/PerceroAgentListener.java @@ -13,6 +13,10 @@ import com.percero.agents.sync.vo.SyncRequest; import com.percero.amqp.handlers.*; import com.percero.framework.accessor.IAccessorService; + +import java.util.HashSet; +import java.util.Set; + import org.apache.log4j.Logger; import org.springframework.amqp.core.AmqpAdmin; import org.springframework.amqp.core.AmqpTemplate; @@ -26,6 +30,7 @@ import org.springframework.core.task.TaskExecutor; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; /** * This class supplies the main method that creates the spring context @@ -145,7 +150,13 @@ else if (ob instanceof AuthRequest) { handleAuthRequest((AuthRequest) ob, key, replyTo); } } catch (Exception e) { - logger.error("Unable to process message", e); + try { + // Attempt to print out the unrecognizable message. + logger.error("Unable to process message: " + new String(message.getBody()), e); + } catch(Exception e1) { + // Else just report the exception. + logger.error("Unable to process message", e); + } } } @@ -356,7 +367,15 @@ else if(key.equals(AuthenticateOAuthAccessTokenRequest.ID) || key.equals("authen else if(key.equals("disconnectAuth")){ if (request instanceof com.percero.agents.auth.vo.DisconnectRequest) { response = new DisconnectResponse(); - result = authService.logoutUser(request.getUserId(), request.getToken(), request.getClientId()); + Set clientIds = new HashSet(); + clientIds.add(request.getClientId()); + if (StringUtils.hasText(((com.percero.agents.auth.vo.DisconnectRequest) request).getExistingClientId())) { + clientIds.add(((com.percero.agents.auth.vo.DisconnectRequest) request).getExistingClientId()); + } + if (((com.percero.agents.auth.vo.DisconnectRequest) request).getExistingClientIds() != null && !((com.percero.agents.auth.vo.DisconnectRequest) request).getExistingClientIds().isEmpty()) { + clientIds.addAll(((com.percero.agents.auth.vo.DisconnectRequest) request).getExistingClientIds()); + } + result = authService.logoutUser(request.getUserId(), request.getToken(), clientIds); ((DisconnectResponse) response).setResult((Boolean)result); } } diff --git a/src/main/java/com/percero/amqp/QueueProperties.java b/src/main/java/com/percero/amqp/QueueProperties.java new file mode 100644 index 0000000..4721744 --- /dev/null +++ b/src/main/java/com/percero/amqp/QueueProperties.java @@ -0,0 +1,54 @@ +package com.percero.amqp; + +import org.joda.time.Instant; + +/** + * Holds basic information about a Message Queue, such as name and number of + * messages. + * + * @author Collin Brown + * + */ +public class QueueProperties { + + String queueName = null; + int numMessages = 0; + int numConsumers = 0; + Instant dateTimeIdleSince = null; + boolean isEolClientsMember = false; + + public String getQueueName() { + return queueName; + } + public void setQueueName(String queueName) { + this.queueName = queueName; + } + public int getNumMessages() { + return numMessages; + } + public void setNumMessages(int numMessages) { + this.numMessages = numMessages; + } + public int getNumConsumers() { + return numConsumers; + } + public void setNumConsumers(int numConsumers) { + this.numConsumers = numConsumers; + } + public Instant getDateTimeIdleSince() { + return dateTimeIdleSince; + } + public void setDateTimeIdleSince(Instant dateTimeIdleSince) { + this.dateTimeIdleSince = dateTimeIdleSince; + } + public boolean isEolClientsMember() { + return isEolClientsMember; + } + public void setEolClientsMember(boolean isEolClientsMember) { + this.isEolClientsMember = isEolClientsMember; + } + public QueueProperties() { + // TODO Auto-generated constructor stub + } + +} diff --git a/src/main/java/com/percero/amqp/RabbitMQPushSyncHelper.java b/src/main/java/com/percero/amqp/RabbitMQPushSyncHelper.java index 2d6a306..d451a82 100644 --- a/src/main/java/com/percero/amqp/RabbitMQPushSyncHelper.java +++ b/src/main/java/com/percero/amqp/RabbitMQPushSyncHelper.java @@ -8,6 +8,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; @@ -16,6 +17,7 @@ import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; @@ -24,6 +26,9 @@ import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper; import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.Instant; +import org.joda.time.MutableDateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.springframework.amqp.AmqpIOException; @@ -32,39 +37,41 @@ import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.core.Queue; -import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer; +import org.springframework.amqp.rabbit.core.ChannelCallback; +import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.ClassMapper; import org.springframework.amqp.support.converter.DefaultClassMapper; import org.springframework.amqp.support.converter.MessageConversionException; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.access.RedisKeyUtils; +import com.percero.agents.sync.cw.CheckChangeWatcherMessage; import com.percero.agents.sync.datastore.ICacheDataStore; import com.percero.agents.sync.services.IPushSyncHelper; import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.agents.sync.vo.ClassIDPair; import com.percero.agents.sync.vo.IJsonObject; import com.percero.agents.sync.vo.PushUpdateResponse; import com.percero.agents.sync.vo.SyncResponse; +import com.percero.framework.vo.IPerceroObject; +import com.rabbitmq.client.AMQP.Queue.DeclareOk; +import com.rabbitmq.client.Channel; import com.rabbitmq.client.ShutdownSignalException; import edu.emory.mathcs.backport.java.util.Arrays; -import org.slf4j.*; - -@Component public class RabbitMQPushSyncHelper implements IPushSyncHelper, ApplicationContextAware { private static Logger logger = Logger.getLogger(RabbitMQPushSyncHelper.class); @@ -91,23 +98,17 @@ public class RabbitMQPushSyncHelper implements IPushSyncHelper, ApplicationConte @Resource AmqpAdmin amqpAdmin; - AbstractMessageListenerContainer rabbitMessageListenerContainer; - @Resource @Qualifier("defaultListenerContainer") - public void setRabbitMessageListenerContainer(AbstractMessageListenerContainer container){ - rabbitMessageListenerContainer = container; - } - // RabbitMQ environment variables. - @Autowired @Value("$pf{gateway.rabbitmq.admin_port:15672}") - int rabbitAdminPort = 15672; - @Autowired @Value("$pf{gateway.rabbitmq.login:guest}") - String rabbitLogin = "guest"; - @Autowired @Value("$pf{gateway.rabbitmq.password:guest}") - String rabbitPassword = "guest"; - @Autowired @Value("$pf{gateway.rabbitmq.host:localhost}") - String rabbitHost = null; - @Autowired @Value("$pf{gateway.rabbitmq.queue_timeout:43200000}") // 8 Hours - long rabbitQueueTimeout = 43200000; + @Value("$pf{gateway.rabbitmq.admin_port:15672}") + int rabbitAdminPort; + @Value("$pf{gateway.rabbitmq.login:guest}") + String rabbitLogin; + @Value("$pf{gateway.rabbitmq.password:guest}") + String rabbitPassword; + @Value("$pf{gateway.rabbitmq.host:localhost}") + String rabbitHost; + @Value("$pf{gateway.rabbitmq.queue_timeout:43200000}") // 8 Hours + long rabbitQueueTimeout; @Autowired ICacheDataStore cacheDataStore; @@ -117,37 +118,31 @@ public void setCacheDataStore(ICacheDataStore cacheDataStore) { @SuppressWarnings("rawtypes") protected void pushJsonToRouting(String objectJson, Class objectClass, String routingKey) { - try{ - - + try { Message convertedMessage = toMessage(objectJson, objectClass, MessageProperties.CONTENT_TYPE_JSON); template.send(routingKey, convertedMessage); } - catch(Exception e){ + catch(Exception e) { logger.error(e.getMessage(), e); } } protected void pushMessageToRouting(Message convertedMessage, String routingKey) { - try{ - - + try { template.send(routingKey, convertedMessage); } - catch(Exception e){ + catch(Exception e) { logger.error(e.getMessage(), e); } } @SuppressWarnings("rawtypes") protected void pushStringToRouting(String objectJson, Class objectClass, String routingKey) { - try{ - - + try { Message convertedMessage = toMessage(objectJson, objectClass, MessageProperties.CONTENT_TYPE_BYTES); template.send(routingKey, convertedMessage); } - catch(Exception e){ + catch(Exception e) { logger.error(e.getMessage(), e); } } @@ -155,8 +150,6 @@ protected void pushStringToRouting(String objectJson, Class objectClass, String @SuppressWarnings("rawtypes") public final Message toMessage(String objectJson, Class objectClass, String contentEncoding) throws MessageConversionException { - - MessageProperties messageProperties = new MessageProperties(); messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON); messageProperties.setContentEncoding(this.defaultCharset); @@ -167,8 +160,6 @@ public final Message toMessage(String objectJson, Class objectClass, String cont @SuppressWarnings("rawtypes") public final Message toMessage(String objectJson, Class objectClass, MessageProperties messageProperties, String contentEncoding) throws MessageConversionException { - - Message message = createMessage(objectJson, objectClass, messageProperties, contentEncoding); return message; } @@ -176,9 +167,6 @@ public final Message toMessage(String objectJson, Class objectClass, MessageProp @SuppressWarnings("rawtypes") protected Message createMessage(String aString, Class objectClass, MessageProperties messageProperties, String contentEncoding) throws MessageConversionException { - - - byte[] bytes = null; try { String jsonString = aString; @@ -190,15 +178,11 @@ protected Message createMessage(String aString, Class objectClass, MessageProper messageProperties.setContentLength(bytes.length); } -// String objectClassName = objectClass.getName(); -// messageProperties.getHeaders().put("__TypeId__", objectClassName); classMapper.fromClass(objectClass, messageProperties); return new Message(bytes, messageProperties); } public void pushSyncResponseToClient(SyncResponse anObject, String clientId) { - - if (anObject != null && StringUtils.hasText(clientId)) { pushJsonToRouting(anObject.toJson(objectMapper), anObject.getClass(), clientId); } @@ -206,8 +190,6 @@ public void pushSyncResponseToClient(SyncResponse anObject, String clientId) { @SuppressWarnings("rawtypes") public void pushSyncResponseToClients(SyncResponse syncResponse, Collection clientIds) { - - if ( syncResponse != null && clientIds != null && !clientIds.isEmpty() ) { Class objectClass = syncResponse.getClass(); @@ -222,8 +204,6 @@ public void pushSyncResponseToClients(SyncResponse syncResponse, Collection listClients) { - - if (anObject != null && listClients != null && !listClients.isEmpty() ) { // Route to specific clients. // Optimization: create the JSON string of the object. @@ -247,17 +227,29 @@ public void pushObjectToClients(Object anObject, Collection listClients) @Override public void pushStringToRoute(String aString, String routeName) { - - if (StringUtils.hasText(routeName)) { pushStringToRouting(aString, String.class, routeName); } } + @Override + public void enqueueCheckChangeWatcher(ClassIDPair classIDPair, String[] fieldNames, String[] params){ + enqueueCheckChangeWatcher(classIDPair, fieldNames, params, null); + } + + @Override + public void enqueueCheckChangeWatcher(ClassIDPair classIDPair, String[] fieldNames, String[] params, IPerceroObject oldValue){ + CheckChangeWatcherMessage message = new CheckChangeWatcherMessage(); + message.classIDPair = classIDPair; + message.fieldNames = fieldNames; + message.params = params; + if(oldValue != null) + message.oldValueJson = ((BaseDataObject)oldValue).toJson(); + template.convertAndSend("checkChangeWatcher", message); + } + @Override public Boolean removeClient(String clientId) { - - try { if (!cacheDataStore.getSetIsMember(RedisKeyUtils.eolClients(), clientId)) { logger.debug("RabbitMQ Removing Client " + clientId); @@ -296,8 +288,6 @@ public Boolean removeClient(String clientId) { } protected Boolean deleteQueue(String queue) { - - try { logger.debug("RabbitMQ Deleting Queue " + queue); Queue clientQueue = new Queue(queue, durableQueues); @@ -317,8 +307,6 @@ protected Boolean deleteQueue(String queue) { @Override public Boolean renameClient(String thePreviousClientId, String clientId) { - - if (!StringUtils.hasText(thePreviousClientId)) { logger.warn("RabbitMQ renameClient previous client not set"); return false; @@ -339,22 +327,41 @@ else if (clientId.equalsIgnoreCase(thePreviousClientId)) { // If we find an EOL Message, then we want to make sure it stays in // the previous queue. Message eolMessage = null; - while ((nextExistingMessage = template.receive(thePreviousClientId)) != null) { - JsonNode messageJsonNode = objectMapper.readTree(nextExistingMessage.getBody()); - if (messageJsonNode.has("EOL")) { - // We found an EOL message, keep hold of it so we can resent - // to the previous queue. - eolMessage = nextExistingMessage; + + final String queueName = thePreviousClientId; + boolean exists = ((RabbitTemplate)template).execute(new ChannelCallback() { + @Override + public DeclareOk doInRabbit(Channel channel) throws Exception { + try { + return channel.queueDeclarePassive(queueName); + } + catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Queue '" + queueName + "' does not exist"); + } + return null; + } + } + }) != null; + + if (exists) { + while ((nextExistingMessage = template.receive(thePreviousClientId)) != null) { + JsonNode messageJsonNode = objectMapper.readTree(nextExistingMessage.getBody()); + if (messageJsonNode.has("EOL")) { + // We found an EOL message, keep hold of it so we can resent + // to the previous queue. + eolMessage = nextExistingMessage; + } + else { + template.send(clientId, nextExistingMessage); + } } - else { - template.send(clientId, nextExistingMessage); + + if (eolMessage != null) { + // Make sure the EOL message is left intact in the old queue. + template.send(thePreviousClientId, eolMessage); } } - - if (eolMessage != null) { - // Make sure the EOL message is left intact in the old queue. - template.send(thePreviousClientId, eolMessage); - } } catch(AmqpIOException e) { // Most likely due to queue already being deleted. Boolean queueDoesNotExist = false; @@ -385,176 +392,319 @@ else if (clientId.equalsIgnoreCase(thePreviousClientId)) { // SCHEDULED TASKS ////////////////////////////////////////////////// - private Boolean validatingQueues = false; + Boolean validatingQueues = false; // @Scheduled(fixedRate=600000) // 10 Minutes // @Scheduled(fixedRate=30000) // 30 Seconds @Scheduled(fixedRate=300000) // 5 Minutes - public void validateQueues() { + public void runValidateQueues() { + validateQueues(); + } + + public boolean validateQueues() { - synchronized (validatingQueues) { if (validatingQueues) { // Currently running. - return; + return false; } else { validatingQueues = true; } } - String host = rabbitHost; - if (!StringUtils.hasText(host)) { - // No Rabbit host configured? Very strange, but no sense in moving forward here... - logger.error("No RabbitMQ host configured?"); - return; + try { + Set queuesToCheck = retrieveQueueProperties(false); // We only want NON system queues. + Set queueNamesToCheck = new HashSet(); + + for(QueueProperties queueProperties : queuesToCheck) { + if (checkQueueForDeletion(queueProperties)) { + deleteQueue(queueProperties.queueName); + } + else if (checkQueueForLogout(queueProperties)) { + // This queue did not pass the test to be deleted, add + // it to the list of valid client queue names to check + // for logout. + queueNamesToCheck.add(queueProperties.queueName); + } + } + + // Check to see if each queue name is a valid client. + if (!queueNamesToCheck.isEmpty()) { + Set validClients = accessManager.validateClients(queueNamesToCheck); + // Remove all valid clients from the queue names. + queueNamesToCheck.removeAll(validClients); + + // Now delete the remaining INVALID queues. + Iterator itrQueuesToDelete = queueNamesToCheck.iterator(); + while (itrQueuesToDelete.hasNext()) { + String nextQueueName = itrQueuesToDelete.next(); + logger.debug("RabbitMQ Logging out client " + nextQueueName); + accessManager.logoutClient(nextQueueName, true); + } + } + + } catch (ClientProtocolException e) { + logger.debug(e); + } catch (IOException e) { + logger.debug(e); + } catch (Exception e) { + logger.warn(e); + } finally { + synchronized (validatingQueues) { + validatingQueues = false; + } } - String uri = "http://" + host + ":" + rabbitAdminPort + "/api/queues/"; + // Loop through EOL queues and delete any that now have no clients. - DefaultHttpClient httpClient = new DefaultHttpClient(); - httpClient.getCredentialsProvider().setCredentials(new AuthScope(host, rabbitAdminPort), new UsernamePasswordCredentials(rabbitLogin, rabbitPassword)); - HttpGet httpGet = new HttpGet(uri); + return true; + } + + protected Set retrieveQueueProperties(boolean includeSystemQueues) throws JsonSyntaxException, ClientProtocolException, IOException { + Set queuesToCheck = new HashSet(); - try { - HttpResponse r = httpClient.execute(httpGet); - StringWriter writer = new StringWriter(); - InputStream is = r.getEntity().getContent(); - String encoding = null; - if (r.getEntity().getContentEncoding() != null) { - encoding = r.getEntity().getContentEncoding().getValue(); - IOUtils.copy(is, writer, encoding); - } - else { - IOUtils.copy(is, writer); - } - String theString = writer.toString(); - + JsonParser parser = new JsonParser(); + JsonElement jsonQueues = parser.parse(retrieveQueuesJsonListAsString()); + JsonArray jsonQueuesArray = jsonQueues.getAsJsonArray(); + + if (jsonQueuesArray != null) { int numQueues = 0; - Set queueNamesToCheck = null; + numQueues = jsonQueuesArray.size(); + logger.debug("Found " + numQueues + " RabbitMQ Queues to validate..."); - JsonParser parser = new JsonParser(); - JsonElement jsonQueues = parser.parse(theString); - JsonArray jsonQueuesArray = jsonQueues.getAsJsonArray(); - - if (jsonQueuesArray != null) { - numQueues = jsonQueuesArray.size(); - logger.debug("Found " + numQueues + " RabbitMQ Queues to validate..."); - queueNamesToCheck = new HashSet(numQueues - queueNames.size()); + Iterator itrJsonQueuesArray = jsonQueuesArray.iterator(); + while (itrJsonQueuesArray.hasNext()) { + JsonElement nextJsonQueue = itrJsonQueuesArray.next(); + JsonObject nextJsonQueueObject = nextJsonQueue.getAsJsonObject(); + + QueueProperties queueProperties = new QueueProperties(); - Iterator itrJsonQueuesArray = jsonQueuesArray.iterator(); - while (itrJsonQueuesArray.hasNext()) { - JsonElement nextJsonQueue = itrJsonQueuesArray.next(); - JsonObject nextJsonQueueObject = nextJsonQueue.getAsJsonObject(); - - JsonElement nextJsonQueueName = nextJsonQueueObject.get("name"); - String nextQueueName = null; - if (nextJsonQueueName != null) { - nextQueueName = nextJsonQueueName.getAsString(); - } - else { + JsonElement nextJsonQueueName = nextJsonQueueObject.get("name"); + if (nextJsonQueueName != null) { + queueProperties.queueName = nextJsonQueueName.getAsString(); + if (!StringUtils.hasText(queueProperties.queueName) || (!includeSystemQueues && queueNames.contains(queueProperties.queueName))) { + // No name OR System Queue -> Ignore continue; } + } + else { + // No queue name, so we can't really do much... + continue; + } - if (cacheDataStore.getSetIsMember(RedisKeyUtils.eolClients(), nextQueueName)) { - JsonElement nextJsonQueueMessages = nextJsonQueueObject.get("messages"); - int nextQueueMessages = 0; - if (nextJsonQueueMessages != null) { - nextQueueMessages = nextJsonQueueMessages.getAsInt(); - - if (nextQueueMessages <= 0) { - logger.debug("Deleting EOL empty queue " + nextQueueName); - deleteQueue(nextQueueName); - continue; - } - } - } - - JsonElement nextJsonQueueConsumers = nextJsonQueueObject.get("consumers"); - if (nextJsonQueueConsumers != null) { - // If the queue has consumers, then leave it alone. - int numConsumers = nextJsonQueueConsumers.getAsInt(); - if (numConsumers == 0) { - // If this queue is in the EOL list, then it can simply be deleted. - if (cacheDataStore.getSetIsMember(RedisKeyUtils.eolClients(), nextQueueName)) { - logger.debug("Deleting EOL no consumers queue " + nextQueueName); - deleteQueue(nextQueueName); - continue; - } - } - else { - // Queue has consumers, so leave alone for now. - continue; + JsonElement nextJsonQueueMessages = nextJsonQueueObject.get("messages"); + if (nextJsonQueueMessages != null) { + queueProperties.numMessages = nextJsonQueueMessages.getAsInt(); + } + + JsonElement nextJsonQueueConsumers = nextJsonQueueObject.get("consumers"); + if (nextJsonQueueConsumers != null) { + // If the queue has consumers, then leave it alone. + queueProperties.numConsumers = nextJsonQueueConsumers.getAsInt(); + } + + JsonElement nextJsonQueueIdleSince = nextJsonQueueObject.get("idle_since"); + if (nextJsonQueueIdleSince != null) { + try { + String strIdleSince = nextJsonQueueIdleSince.getAsString(); + DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); + MutableDateTime dateTime = formatter.withOffsetParsed().parseMutableDateTime(strIdleSince); + if (dateTime != null) { + dateTime.setZoneRetainFields(DateTimeZone.UTC); + queueProperties.dateTimeIdleSince = dateTime.toInstant(); } + } catch(Exception e) { + logger.debug("Error getting idle since for queue " + queueProperties.queueName, e); } - - JsonElement nextJsonQueueIdleSince = nextJsonQueueObject.get("idle_since"); - if (nextJsonQueueIdleSince != null) { - try { - String strIdleSince = nextJsonQueueIdleSince.getAsString(); - DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); - DateTime dateTime = formatter.withOffsetParsed().parseDateTime(strIdleSince); - if (dateTime != null) { - DateTime currentDateTime = new DateTime(System.currentTimeMillis()); - currentDateTime = currentDateTime.toDateTime(dateTime.getZone()); - long timeDiffInMs = currentDateTime.toDate().getTime() - dateTime.toDate().getTime(); - if (timeDiffInMs < rabbitQueueTimeout) { - // Queue has NOT timed out yet. - continue; - } - } - } catch(Exception e) { - // Do nothing - logger.debug("Error getting idle since for queue " + nextQueueName, e); - continue; - } + } + else { + logger.debug("Unable to determine idle since time, ignoring queue " + queueProperties.queueName); + } + + queueProperties.isEolClientsMember = cacheDataStore.getSetIsMember(RedisKeyUtils.eolClients(), queueProperties.queueName); + + queuesToCheck.add(queueProperties); + } + } + + return queuesToCheck; + } + + protected String retrieveQueuesJsonListAsString() throws ClientProtocolException, IOException { + String host = rabbitHost; + if (!StringUtils.hasText(host)) { + // No Rabbit host configured? Very strange, but no sense in moving forward here... + logger.error("No RabbitMQ host configured?"); + return ""; + } + + String uri = "http://" + host + ":" + rabbitAdminPort + "/api/queues/"; + return issueHttpCall(uri, new AuthScope(host, rabbitAdminPort), new UsernamePasswordCredentials(rabbitLogin, rabbitPassword)); + } + + protected String issueHttpCall(String uri, AuthScope authScope, Credentials credentials) throws ClientProtocolException, IOException { + DefaultHttpClient httpClient = new DefaultHttpClient(); + httpClient.getCredentialsProvider().setCredentials(authScope , credentials); + HttpGet httpGet = new HttpGet(uri); + + HttpResponse r = httpClient.execute(httpGet); + StringWriter writer = new StringWriter(); + InputStream is = r.getEntity().getContent(); + String encoding = null; + if (r.getEntity().getContentEncoding() != null) { + encoding = r.getEntity().getContentEncoding().getValue(); + IOUtils.copy(is, writer, encoding); + } + else { + IOUtils.copy(is, writer); + } + return writer.toString(); + } + + protected boolean checkQueueForDeletion(QueueProperties queueProperties) { + return checkQueueForDeletion(queueProperties.queueName, queueProperties.numMessages, queueProperties.numConsumers, queueProperties.dateTimeIdleSince, queueProperties.isEolClientsMember); + } + + /** + * For each existing queue, the queue can be deleted when the following are true: + * 1. The queue is NOT a system queue {@link #queueNames} + * 1. The queue is in the list of EOL Clients {@link RedisKeyUtils#eolClients()} AND + * 1. There are NO messages left in the queue + * OR + * 2. There are NO consumers of the queue + * OR + * 2. The queue has been idle for at least {@link #rabbitQueueTimeout} milliseconds AND + * the queue has no consumers and has contains an EOL message + * In this case, we are assuming that this is a queue for a client that has gone away + * and is never coming back. This timeout should be in the number of days/weeks range. + * + * @param queueName + * @param numMessages + * @param numConsumers + * @param dateTimeIdleSince + * @param isEolClientsMember + * @return + */ + protected boolean checkQueueForDeletion(String queueName, int numMessages, int numConsumers, Instant dateTimeIdleSince, boolean isEolClientsMember) { + if (queueNames.contains(queueName)) { + return false; + } + + if (isEolClientsMember && (numMessages == 0 || numConsumers == 0)) { + logger.debug("Deleting EOL empty queue " + queueName + ": EOL Client with " + numMessages + " Messages and " + numConsumers + " Consumers"); + return true; + } + + if (numConsumers == 0 && numMessages > 0 && queueHasTimedOut(queueName, dateTimeIdleSince)) { + // If this queue has an EOL message and has no + // consumers, then we can safely delete it. + // If we have gotten here then client is NOT in + // the EOL list, thus it is old and can safely + // be deleted. + Message nextExistingMessage = null; + + // If we find an EOL Message, + Message eolMessage = null; + List messagesToRequeue = new ArrayList<>(); + while ((nextExistingMessage = template.receive(queueName)) != null) { + try { + JsonNode messageJsonNode = objectMapper.readTree(nextExistingMessage.getBody()); + if (messageJsonNode.has("EOL") && messageJsonNode.get("EOL").getBooleanValue()) { + // We found an EOL message -> This queue to be deleted. + eolMessage = nextExistingMessage; + break; } else { - logger.debug("Unable to determine idle since time, ignoring queue " + nextQueueName); - continue; - } - - if (StringUtils.hasText(nextQueueName)) { - // Check to see if this queue still valid. - if (!queueNames.contains(nextQueueName)) { - // Valid Queue, used by system. - queueNamesToCheck.add(nextQueueName); - } + // Re-queue this message... + messagesToRequeue.add(nextExistingMessage); } + } catch (IOException e) { + logger.warn("Error reading queue " + queueName + " message, unable to process"); } - - // Check to see if each queue name is a valid client. - if (!queueNamesToCheck.isEmpty()) { - Set validClients = accessManager.validateClients(queueNamesToCheck); - // Remove all valid clients from the queue names. - queueNamesToCheck.removeAll(validClients); - - // Now delete the remaining INVALID queues. - Iterator itrQueuesToDelete = queueNamesToCheck.iterator(); - while (itrQueuesToDelete.hasNext()) { - String nextQueueName = itrQueuesToDelete.next(); - logger.debug("RabbitMQ Logging out client " + nextQueueName); - accessManager.logoutClient(nextQueueName, true); - } + } + + if (eolMessage != null) { + logger.debug("Deleting EOL no consumers queue " + queueName + ": EOL Client WITH EOL Message"); + return true; + } + else { + // Need to re-queue the messages. + for(Message nextMessage : messagesToRequeue) { + template.send(queueName, nextMessage); } } + } - } catch (ClientProtocolException e) { - logger.debug(e); - } catch (IOException e) { - logger.debug(e); - } catch (Exception e) { - logger.warn(e); - } finally { - synchronized (validatingQueues) { - validatingQueues = false; + return false; + } + + protected boolean checkQueueForLogout(QueueProperties queueProperties) { + return checkQueueForLogout(queueProperties.queueName, queueProperties.numMessages, queueProperties.numConsumers, queueProperties.dateTimeIdleSince, queueProperties.isEolClientsMember); + } + + /** + * If a queue meets this criteria, then it should be further investigated for automatic logout. + * 1. The queue is NOT a system queue {@link #queueNames} + * 2. Is NOT a member of EOL Clients list + * 3. Has NO consumers + * 4. The queue has been idle for at least {@link #rabbitQueueTimeout} milliseconds + * In this case, we are assuming that this is a queue for a client that has gone away + * and is never coming back. This timeout should be in the number of days/weeks range. + * + * @param queueName + * @param numMessages + * @param numConsumers + * @param dateTimeIdleSince + * @param isEolClientsMember + * @return + */ + protected boolean checkQueueForLogout(String queueName, int numMessages, int numConsumers, Instant dateTimeIdleSince, boolean isEolClientsMember) { + if (queueNames.contains(queueName)) { + return false; + } + + if (!isEolClientsMember) { + if (numConsumers <= 0) { + if (queueHasTimedOut(queueName, dateTimeIdleSince)) { + // Queue HAS timed out. + logger.debug("Queue Timed Out: " + queueName); + return true; + } } } - // Loop through EOL queues and delete any that now have no clients. - + return false; } - private Collection queueNames = null; + /** + * If the queue has been idle for at least {@link #rabbitQueueTimeout} milliseconds then returns true. + * + * @param queueName + * @param dateTimeIdleSince + * @return + */ + protected boolean queueHasTimedOut(String queueName, Instant dateTimeIdleSince) { + if (queueNames.contains(queueName)) { + // System queues can NEVER timeout. + return false; + } + + boolean queueHasTimedOut = false; + if (dateTimeIdleSince != null) { + DateTime currentDateTime = new DateTime(System.currentTimeMillis()); + currentDateTime = currentDateTime.toDateTime(dateTimeIdleSince.getZone()); + long timeDiffInMs = currentDateTime.toDate().getTime() - dateTimeIdleSince.toDate().getTime(); + if (timeDiffInMs > rabbitQueueTimeout) { + // Queue HAS timed out. + logger.debug("Queue Timed Out: " + queueName); + + queueHasTimedOut = true; + } + } + return queueHasTimedOut; + } + + Collection queueNames = null; private ApplicationContext applicationContext = null; @SuppressWarnings("unchecked") @@ -585,5 +735,5 @@ public void setApplicationContext(ApplicationContext applicationContext) queueNames.add(nextQueue.getName()); } } - + } \ No newline at end of file diff --git a/src/main/java/com/percero/amqp/handlers/FindByExampleHandler.java b/src/main/java/com/percero/amqp/handlers/FindByExampleHandler.java index d283d95..738235c 100644 --- a/src/main/java/com/percero/amqp/handlers/FindByExampleHandler.java +++ b/src/main/java/com/percero/amqp/handlers/FindByExampleHandler.java @@ -1,10 +1,13 @@ package com.percero.amqp.handlers; +import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.agents.sync.vo.ClassIDPair; import com.percero.agents.sync.vo.FindByExampleRequest; import com.percero.agents.sync.vo.FindByExampleResponse; import com.percero.agents.sync.vo.SyncRequest; @@ -24,8 +27,29 @@ public FindByExampleHandler() { public SyncResponse handleMessage(SyncRequest request, String replyTo) throws Exception { FindByExampleResponse response = new FindByExampleResponse(); FindByExampleRequest findByExampleRequest = (FindByExampleRequest) request; - Object result = syncAgentService.findByExample(findByExampleRequest.getTheObject(), null, findByExampleRequest.getClientId()); + String originalId = null; + if (StringUtils.hasText(findByExampleRequest.getTheObject().getID())) { + originalId = findByExampleRequest.getTheObject().getID(); + findByExampleRequest.getTheObject().setID(null); + } + List result = (List) syncAgentService.findByExample(findByExampleRequest.getTheObject(), null, findByExampleRequest.getClientId()); response = new FindByExampleResponse(); + + if (result == null || result.isEmpty()) { + if (originalId != null) { + // Couldn't find by example, but if the original object had an ID, let's try and find by id. + BaseDataObject findByIdResult = (BaseDataObject) syncAgentService.findById( + new ClassIDPair(originalId, findByExampleRequest.getTheObject().getClass().getCanonicalName()), + findByExampleRequest.getClientId()); + if (findByIdResult != null) { + if (result == null) { + result = new ArrayList(); + } + result.add(findByIdResult); + } + } + } + ((FindByExampleResponse)response).setResult((List)result); return response; diff --git a/src/main/java/com/percero/amqp/handlers/ReconnectHandler.java b/src/main/java/com/percero/amqp/handlers/ReconnectHandler.java index ac3a4d2..f6083a6 100644 --- a/src/main/java/com/percero/amqp/handlers/ReconnectHandler.java +++ b/src/main/java/com/percero/amqp/handlers/ReconnectHandler.java @@ -91,14 +91,16 @@ public SyncResponse handleMessage(SyncRequest request, String replyTo) throws Ex reconnectRequest.getExistingClientIds()[0] = reconnectRequest.getExistingClientId(); } + String matchingClientId = null; for(int i=0; i itrExistingClientIds = existingClientIds.iterator(); - while (itrExistingClientIds.hasNext()) { - String existingClientId = itrExistingClientIds.next(); - if (existingClientId.equalsIgnoreCase(replyTo)) { - // We have already retrieved the Journals for this client IDs. - continue; + if (existingClientIds != null && !existingClientIds.isEmpty()) { + Iterator itrExistingClientIds = existingClientIds.iterator(); + while (itrExistingClientIds.hasNext()) { + String existingClientId = itrExistingClientIds.next(); + if (existingClientId.equalsIgnoreCase(replyTo)) { + // We have already retrieved the Journals for this client IDs. + continue; + } + + // ExistingClientId is different than new clientId, need to transfer all messages from old queue and then remove that queue. + log.debug("Renaming client " + existingClientId + " to " + replyTo); + pushSyncHelper.renameClient(existingClientId, replyTo); + + // TODO: Do we need to also get updates/deletes for existingClientId? + + // Push all UpdateJournals for this Client. + updateJournals.addAll( accessManager.getClientUpdateJournals(existingClientId, true) ); + log.debug((updateJournals != null ? updateJournals.size() : 0) + " updateJournal(s) for Client"); + + // Push all DeleteJournals for this Client. + deleteJournals.addAll( accessManager.getClientDeleteJournals(existingClientId, true) ); + log.debug((deleteJournals != null ? deleteJournals.size() : 0) + " deleteJournal(s) for Client"); } - - // ExistingClientId is different than new clientId, need to transfer all messages from old queue and then remove that queue. - log.debug("Renaming client " + existingClientId + " to " + replyTo); - pushSyncHelper.renameClient(existingClientId, replyTo); - - // TODO: Do we need to also get updates/deletes for existingClientId? - - // Push all UpdateJournals for this Client. - updateJournals.addAll( accessManager.getClientUpdateJournals(existingClientId, true) ); - log.debug((updateJournals != null ? updateJournals.size() : 0) + " updateJournal(s) for Client"); - - // Push all DeleteJournals for this Client. - deleteJournals.addAll( accessManager.getClientDeleteJournals(existingClientId, true) ); - log.debug((deleteJournals != null ? deleteJournals.size() : 0) + " deleteJournal(s) for Client"); } // syncAgentService.pushClientUpdateJournals(reconnectRequest.getClientId(), updateJournals); diff --git a/src/main/java/com/percero/amqp/handlers/SyncMessageHandler.java b/src/main/java/com/percero/amqp/handlers/SyncMessageHandler.java index 3910d7a..c38f994 100644 --- a/src/main/java/com/percero/amqp/handlers/SyncMessageHandler.java +++ b/src/main/java/com/percero/amqp/handlers/SyncMessageHandler.java @@ -43,7 +43,12 @@ public void run(SyncRequest request, String replyTo) { response = handleMessage(request, replyTo); } catch(SyncException e) { if (ClientException.INVALID_CLIENT.equals(e.getName())) { - log.debug("Invalid Client - Setting response to NULL", e); + if (e instanceof ClientException) { + log.debug("Invalid Client (" + ((ClientException) e).getClientId() + ") - Setting response to NULL", e); + } + else { + log.debug("Invalid Client - Setting response to NULL", e); + } // No need to send a response to an invalid client. response = null; diff --git a/src/main/java/com/percero/datasource/BaseConnectionFactory.java b/src/main/java/com/percero/datasource/BaseConnectionFactory.java index 440725e..e16664b 100644 --- a/src/main/java/com/percero/datasource/BaseConnectionFactory.java +++ b/src/main/java/com/percero/datasource/BaseConnectionFactory.java @@ -169,6 +169,7 @@ public void init() throws PropertyVetoException{ // Default to Hikari Connection Pool. HikariConfig config = new HikariConfig(); config.setDriverClassName(driverClassName); + config.setRegisterMbeans(true); config.setJdbcUrl(jdbcUrl); config.setUsername(username); config.setPassword(password); diff --git a/src/main/java/com/percero/hibernate/types/DateBigIntType.java b/src/main/java/com/percero/hibernate/types/DateBigIntType.java index f2ba5c2..2c8ddeb 100644 --- a/src/main/java/com/percero/hibernate/types/DateBigIntType.java +++ b/src/main/java/com/percero/hibernate/types/DateBigIntType.java @@ -3,14 +3,17 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Types; import java.util.Date; import org.hibernate.type.BigIntegerType; -import org.hibernate.type.DateType; public class DateBigIntType extends BigIntegerType { + /** + * + */ + private static final long serialVersionUID = -5880508702368203232L; + public Object get(ResultSet rs, String name) throws SQLException { long value = rs.getLong(name); @@ -27,8 +30,4 @@ public void set(PreparedStatement stmt, Object value, int index) else stmt.setLong(index, ((Date) value).getTime()); } - - public int sqlType() { - return Types.BIGINT; - } } diff --git a/src/main/java/com/percero/hibernate/types/TextType.java b/src/main/java/com/percero/hibernate/types/TextType.java deleted file mode 100644 index 87531ff..0000000 --- a/src/main/java/com/percero/hibernate/types/TextType.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.percero.hibernate.types; - -import java.sql.Types; - -public class TextType extends org.hibernate.type.TextType { - - public int sqlType() { - return Types.BLOB; - } -} diff --git a/src/main/java/com/percero/serial/BDOSerializer.java b/src/main/java/com/percero/serial/BDOSerializer.java index d05651b..8ae2064 100644 --- a/src/main/java/com/percero/serial/BDOSerializer.java +++ b/src/main/java/com/percero/serial/BDOSerializer.java @@ -8,8 +8,6 @@ import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; -import org.hibernate.collection.PersistentBag; -import org.hibernate.proxy.HibernateProxy; import com.percero.agents.sync.metadata.MappedClass; import com.percero.agents.sync.metadata.MappedClassManagerFactory; @@ -36,12 +34,6 @@ public void serialize(BaseDataObject ob, JsonGenerator gen, SerializerProvider a try { List listToAdd = new ArrayList(); List nextFieldList = (List) nextMappedField.getGetter().invoke(ob); - if (nextFieldList instanceof PersistentBag) { - if (((PersistentBag) nextFieldList).getSession() == null || ((PersistentBag) nextFieldList).getSession().isClosed()) { - // The session is closed, so this ain't gonna work... - continue; - } - } for(IPerceroObject nextListObject : nextFieldList) { listToAdd.add(new ClassIDPair(nextListObject.getID(), nextListObject.getClass().getName())); } @@ -52,11 +44,8 @@ public void serialize(BaseDataObject ob, JsonGenerator gen, SerializerProvider a } else if (nextMappedField instanceof MappedFieldPerceroObject) { try { IPerceroObject nextFieldPerceroObject = (IPerceroObject) nextMappedField.getGetter().invoke(ob); - if (!(nextFieldPerceroObject instanceof HibernateProxy)) { - // Only include NOT a HibernateProxy - ClassIDPair nextFieldPair = new ClassIDPair(nextFieldPerceroObject.getID(), nextFieldPerceroObject.getClass().getName()); - pair.addProperty(nextMappedField.getField().getName(), nextFieldPair); - } + ClassIDPair nextFieldPair = new ClassIDPair(nextFieldPerceroObject.getID(), nextFieldPerceroObject.getClass().getName()); + pair.addProperty(nextMappedField.getField().getName(), nextFieldPair); } catch(Exception e) { // Do nothing, for now. } diff --git a/src/main/java/com/percero/serial/JsonUtils.java b/src/main/java/com/percero/serial/JsonUtils.java index feefad6..58e7400 100644 --- a/src/main/java/com/percero/serial/JsonUtils.java +++ b/src/main/java/com/percero/serial/JsonUtils.java @@ -2,8 +2,10 @@ import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; @@ -13,6 +15,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.vo.IJsonObject; import com.percero.framework.vo.IPerceroObject; public class JsonUtils { @@ -222,4 +225,16 @@ public static List getJsonListPerceroObject(JsonObject return result; } + @SuppressWarnings("rawtypes") + static final Map iJsonObjectAssignableClasses = new HashMap(); + @SuppressWarnings("rawtypes") + public static boolean isClassAssignableFromIJsonObject(Class clazz) { + Boolean result = iJsonObjectAssignableClasses.get(clazz); + if (result == null) { + result = IJsonObject.class.isAssignableFrom(clazz); + iJsonObjectAssignableClasses.put(clazz, result); + } + return result; + } + } diff --git a/src/main/java/com/percero/util/MappedClassUtils.java b/src/main/java/com/percero/util/MappedClassUtils.java new file mode 100644 index 0000000..389906a --- /dev/null +++ b/src/main/java/com/percero/util/MappedClassUtils.java @@ -0,0 +1,91 @@ +package com.percero.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class MappedClassUtils { + + @SuppressWarnings("rawtypes") + private static final Map> classFieldsByClass = new ConcurrentHashMap>(); + + @SuppressWarnings("rawtypes") + public static List getClassFields(Class theClass) { + List fieldList = classFieldsByClass.get(theClass); + if (fieldList == null) { + fieldList = new ArrayList(); + classFieldsByClass.put(theClass, fieldList); + + Field[] theFields = theClass.getDeclaredFields(); + for(Field nextField : theFields) { + boolean isStatic = Modifier.STATIC == (nextField.getModifiers() & Modifier.STATIC); + if (!isStatic) + fieldList.add(nextField); + } + + if (theClass.getSuperclass() != null) + fieldList.addAll(getClassFields(theClass.getSuperclass())); + } + + return fieldList; + } + + @SuppressWarnings("rawtypes") + private static final Map> classGetterMethods = new ConcurrentHashMap>(); + + @SuppressWarnings("rawtypes") + private static Map retrieveClassMethods(Class theClass) { + Map classMethods = classGetterMethods.get(theClass); + if (classMethods == null) { + classMethods = new ConcurrentHashMap(); + classGetterMethods.put(theClass, classMethods); + + Method[] theMethods = theClass.getMethods(); + for(Method nextMethod : theMethods) { + // We are storing lower case name for easy compare + classMethods.put(nextMethod.getName().toLowerCase(), nextMethod); + } + } + + return classMethods; + } + + @SuppressWarnings("rawtypes") + public static Method getFieldGetters(Class theClass, Field theField) { + Method theMethod = null; + String theModifiedFieldName = theField.getName(); + if (theModifiedFieldName.indexOf("_") == 0) + theModifiedFieldName = theModifiedFieldName.substring(1); + + String getterMethodName = (new StringBuilder("get").append(theModifiedFieldName.toLowerCase())).toString(); + + Map methods = retrieveClassMethods(theClass); + if (methods != null && !methods.isEmpty()) { + theMethod = methods.get(getterMethodName); + } + + return theMethod; + } + + @SuppressWarnings("rawtypes") + public static Method getFieldSetters(Class theClass, Field theField) { + Method theMethod = null; + String theModifiedFieldName = theField.getName(); + if (theModifiedFieldName.indexOf("_") == 0) + theModifiedFieldName = theModifiedFieldName.substring(1); + + String setterMethodName = (new StringBuilder("set").append(theModifiedFieldName.toLowerCase())).toString(); + + Map methods = retrieveClassMethods(theClass); + if (methods != null && !methods.isEmpty()) { + theMethod = methods.get(setterMethodName); + } + + return theMethod; + } + +} diff --git a/src/main/resources/spring/basic_components_spring_config.xml b/src/main/resources/spring/basic_components_spring_config.xml index fe34a72..d28a918 100644 --- a/src/main/resources/spring/basic_components_spring_config.xml +++ b/src/main/resources/spring/basic_components_spring_config.xml @@ -110,11 +110,6 @@ - @@ -135,6 +130,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -179,7 +219,7 @@ @@ -210,92 +250,10 @@ - + class="org.springframework.orm.hibernate5.HibernateTransactionManager"> - - - diff --git a/src/main/resources/spring/messageListener-spring-config.xml b/src/main/resources/spring/messageListener-spring-config.xml index 024bd01..04f7383 100644 --- a/src/main/resources/spring/messageListener-spring-config.xml +++ b/src/main/resources/spring/messageListener-spring-config.xml @@ -18,50 +18,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/spring/percero-spring-config.xml b/src/main/resources/spring/percero-spring-config.xml index 091f759..38c7038 100644 --- a/src/main/resources/spring/percero-spring-config.xml +++ b/src/main/resources/spring/percero-spring-config.xml @@ -17,53 +17,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/test/java/com/percero/agents/auth/services/TestAuthService.java b/src/test/java/com/percero/agents/auth/services/TestAuthService.java new file mode 100644 index 0000000..d69df05 --- /dev/null +++ b/src/test/java/com/percero/agents/auth/services/TestAuthService.java @@ -0,0 +1,217 @@ +package com.percero.agents.auth.services; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.Mockito; + +import com.percero.agents.auth.vo.AuthProvider; +import com.percero.agents.auth.vo.ServiceUser; +import com.percero.agents.auth.vo.UserAccount; + +public class TestAuthService { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + AuthService authService; + ServiceUser facebookServiceUser; + ServiceUser googleServiceUser; + ServiceUser githubServiceUser; + ServiceUser linkedInServiceUser; + + @Before + public void setUp() throws Exception { + authService = Mockito.mock(AuthService.class); + authService.anonAuthEnabled = false; + + // Setup Facebook Helper + authService.facebookHelper = Mockito.mock(FacebookHelper.class); + facebookServiceUser = new ServiceUser(); + facebookServiceUser.setAuthProviderID(AuthProvider.FACEBOOK.name()); + Mockito.when(authService.facebookHelper.getServiceUser(Mockito.anyString(), Mockito.anyString())).thenReturn(facebookServiceUser); + + // Setup Google Helper + authService.googleHelper = Mockito.mock(GoogleHelper.class); + googleServiceUser = new ServiceUser(); + googleServiceUser.setAuthProviderID(AuthProvider.GOOGLE.name()); + Mockito.when(authService.googleHelper.authenticateAccessToken(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(googleServiceUser); + + // Setup Github Helper + authService.githubHelper = Mockito.mock(GitHubHelper.class); + githubServiceUser = new ServiceUser(); + githubServiceUser.setAuthProviderID(AuthProvider.GITHUB.name()); + Mockito.when(authService.githubHelper.getServiceUser(Mockito.anyString(), Mockito.anyString())).thenReturn(githubServiceUser); + + // Setup LinkedIn Helper + authService.linkedInHelper = Mockito.mock(LinkedInHelper.class); + linkedInServiceUser = new ServiceUser(); + linkedInServiceUser.setAuthProviderID(AuthProvider.LINKEDIN.name()); + Mockito.when(authService.linkedInHelper.getServiceUser(Mockito.anyString(), Mockito.anyString())).thenReturn(linkedInServiceUser); + + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testGetServiceProviderServiceUserUserAccountString() { + Mockito.when(authService.getServiceProviderServiceUser(Mockito.any(UserAccount.class), Mockito.anyString())).thenCallRealMethod(); + Mockito.when(authService.getServiceProviderServiceUser(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenCallRealMethod(); + + UserAccount userAccount = new UserAccount(); + userAccount.setAccessToken("ACCESS_TOKEN"); + userAccount.setAccountId("ACCOUNT_ID"); + userAccount.setRefreshToken("REFRESH_TOKEN"); + + // authService.getServiceProviderServiceUser(userAccount, + // AuthProvider.FACEBOOK.name()) is just a wrapper function, so as long + // as it returns a ServiceUser it is valid. + ServiceUser resultingServiceUser = authService.getServiceProviderServiceUser(userAccount, AuthProvider.FACEBOOK.name()); + assertNotNull(resultingServiceUser); + assertSame(facebookServiceUser, resultingServiceUser); + assertEquals(AuthProvider.FACEBOOK.name(), resultingServiceUser.getAuthProviderID()); + } + + @Test + public void testGetServiceProviderServiceUserStringStringStringString() { + Mockito.when(authService.getServiceProviderServiceUser(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenCallRealMethod(); + + String accessToken = "ACCESS_TOKEN"; + String refreshToken = "REFRESH_TOKEN"; + String accountId = "ACCOUNT_ID"; + String authProviderID = "NONE"; + + // Test finding Auth Provider by name + + // FACEBOOK + authProviderID = "FacEBooK"; // Case should NOT matter. + ServiceUser resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(facebookServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.FACEBOOK.name(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(facebookServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.FACEBOOK.toString(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(facebookServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + // GOOGLE + authProviderID = "gOOgle"; // Case should NOT matter. + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(googleServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.GOOGLE.name(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(googleServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.GOOGLE.toString(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(googleServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + // GITHUB + authProviderID = "gIThub"; // Case should NOT matter. + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(githubServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.GITHUB.name(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(githubServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.GITHUB.toString(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(githubServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + // LINKEDIN + authProviderID = "lINKEDin"; // Case should NOT matter. + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(linkedInServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.LINKEDIN.name(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(linkedInServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.LINKEDIN.toString(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertSame(linkedInServiceUser, resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + // ANON + authService.anonAuthEnabled = false; + authService.anonAuthCode = null; + authProviderID = "aNOn"; // Case should NOT matter. + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNull(resultingServiceUser); + + authService.anonAuthEnabled = true; + authService.anonAuthCode = refreshToken; + authProviderID = "aNOn"; // Case should NOT matter. + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.ANON.name(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.ANON.toString(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + + authProviderID = AuthProvider.ANON.name(); + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNotNull(resultingServiceUser); + assertEquals(authProviderID, resultingServiceUser.getAuthProviderID()); + assertEquals(refreshToken, resultingServiceUser.getRefreshToken()); + + // INVALID + authService.anonAuthEnabled = true; + authService.anonAuthCode = refreshToken; + authProviderID = "InvALID"; // Case should NOT matter. + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNull(resultingServiceUser); + + authService.anonAuthEnabled = false; // ANON should not impact INVALID auth provider ID. + authService.anonAuthCode = null; + authProviderID = "InvALID"; // Case should NOT matter. + resultingServiceUser = authService.getServiceProviderServiceUser(accessToken, refreshToken, accountId, authProviderID); + assertNull(resultingServiceUser); + } + +} 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 1d57a6f..d5e8d34 100644 --- a/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java +++ b/src/test/java/com/percero/agents/sync/jobs/UpdateTableProcessorTest.java @@ -25,8 +25,6 @@ @ContextConfiguration(locations = { "classpath:spring/update_table_processor.xml" }) public class UpdateTableProcessorTest { - @Autowired - UpdateTableConnectionFactory connectionFactory; @Autowired UpdateTablePoller poller; @Autowired @@ -34,10 +32,22 @@ public class UpdateTableProcessorTest { @Autowired AuthUtil authUtil; + UpdateTableConnectionFactory connectionFactory = null; String tableName = "update_table"; @Before public void before() throws Exception{ + + connectionFactory = new UpdateTableConnectionFactory(); + connectionFactory.setDriverClassName("com.mysql.jdbc.Driver"); + connectionFactory.setJdbcUrl("jdbc:mysql://localhost:3306/as_Example?autoReconnect=true"); + connectionFactory.setUsername("root"); + connectionFactory.setPassword("root"); + connectionFactory.setRowIdColumnName("rowID"); + connectionFactory.setLockIdColumnName("lockID"); + connectionFactory.setLockDateColumnName("lockDate"); + connectionFactory.setTimestampColumnName("timestamp"); + // Disable the poller so it doesn't step on our toes poller.enabled = false; cleanerUtil.cleanAll(); @@ -50,28 +60,28 @@ public void before() throws Exception{ } } - @Test + @SuppressWarnings("rawtypes") + @Test public void getClassForTableName_NoTableAnnotation() throws Exception{ - UpdateTableConnectionFactory connectionFactory = new UpdateTableConnectionFactory(); UpdateTableProcessor processor = poller.getProcessor(connectionFactory, tableName); - List clazz = processor.getClassesForTableName("Email"); - Assert.assertEquals(Email.class, clazz); + List clazzes = processor.getClassesForTableName("Email"); + Assert.assertTrue(clazzes.contains(Email.class)); } + @SuppressWarnings("rawtypes") @Test public void getClassForTableName_TableAnnotation() throws Exception{ - UpdateTableConnectionFactory connectionFactory = new UpdateTableConnectionFactory(); UpdateTableProcessor processor = poller.getProcessor(connectionFactory, tableName); - List clazz = processor.getClassesForTableName("Person"); - Assert.assertEquals(Person.class, clazz); + List clazzes = processor.getClassesForTableName("Person"); + Assert.assertTrue(clazzes.contains(Person.class)); } + @SuppressWarnings("rawtypes") @Test public void getClassForTableName_NotFound() throws Exception{ - UpdateTableConnectionFactory connectionFactory = new UpdateTableConnectionFactory(); UpdateTableProcessor processor = poller.getProcessor(connectionFactory, tableName); - List clazz = processor.getClassesForTableName("NotAnEntity"); - Assert.assertNull(clazz); + List clazzes = processor.getClassesForTableName("NotAnEntity"); + Assert.assertTrue(clazzes.isEmpty()); } // Shared setup method @@ -90,7 +100,6 @@ public void setupThreeRowsInUpdateTable() throws SQLException{ @Test public void getRow() throws Exception { setupThreeRowsInUpdateTable(); - UpdateTableConnectionFactory connectionFactory = new UpdateTableConnectionFactory(); UpdateTableProcessor processor = poller.getProcessor(connectionFactory, tableName); List rows = processor.getRows(1); UpdateTableRow row = rows.get(0); @@ -116,7 +125,6 @@ public void getRow() throws Exception { public void processMultipleRows() throws Exception { setupThreeRowsInUpdateTable(); - UpdateTableConnectionFactory connectionFactory = new UpdateTableConnectionFactory(); UpdateTableProcessor processor = poller.getProcessor(connectionFactory, tableName); // ProcessorResult result = processor.run(); // Assert.assertEquals(3, result.getTotal()); diff --git a/src/test/java/com/percero/agents/sync/metadata/TestMappedClass.java b/src/test/java/com/percero/agents/sync/metadata/TestMappedClass.java new file mode 100644 index 0000000..37a199b --- /dev/null +++ b/src/test/java/com/percero/agents/sync/metadata/TestMappedClass.java @@ -0,0 +1,217 @@ +package com.percero.agents.sync.metadata; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Map; + +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.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +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.example.CountryPermit; +import com.percero.example.ExampleManifest; +import com.percero.example.Person; +import com.percero.example.PostalAddress; +import com.percero.example.ShippingAddress; +import com.percero.framework.bl.IManifest; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:spring/percero-spring-config.xml" }) +public class TestMappedClass { + + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testProcessManifest() { + IManifest manifest = new ExampleManifest(); + MappedClass.processManifest(manifest); + + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass personMappedClass = mcm.getMappedClassByClassName(Person.class.getCanonicalName()); + assertNotNull(personMappedClass); + + MappedClass countryPermitMappedClass = mcm.getMappedClassByClassName(CountryPermit.class.getCanonicalName()); + assertNotNull(countryPermitMappedClass); + + // Check one-to-one relationship on class. + MappedClass postalAddressMappedClass = mcm.getMappedClassByClassName(PostalAddress.class.getCanonicalName()); + assertNotNull(postalAddressMappedClass); + + Map nulledOnRemoveFieldReferences = postalAddressMappedClass.getNulledOnRemoveFieldReferences(); + assertNotNull(nulledOnRemoveFieldReferences); + assertEquals(1, nulledOnRemoveFieldReferences.size()); + + Map.Entry nextEntry = nulledOnRemoveFieldReferences.entrySet().iterator().next(); + MappedField nextKey = nextEntry.getKey(); + assertNotNull(nextKey); + assertTrue(nextKey instanceof MappedFieldPerceroObject); + assertEquals("issuerAddress", nextKey.getField().getName()); + assertNotNull(nextKey.getReverseMappedField()); + + MappedField nextValue = nextEntry.getValue(); + assertNotNull(nextKey); + assertTrue(nextValue instanceof MappedFieldPerceroObject); + assertEquals("countryPermit", nextValue.getField().getName()); + assertNotNull(nextValue.getReverseMappedField()); + + // Check one-to-one relationship on parent class. + MappedClass shippingAddressMappedClass = mcm.getMappedClassByClassName(ShippingAddress.class.getCanonicalName()); + assertNotNull(shippingAddressMappedClass); + assertSame(postalAddressMappedClass, shippingAddressMappedClass.parentMappedClass); + assertTrue(postalAddressMappedClass.getChildMappedClasses().contains(shippingAddressMappedClass)); + + nulledOnRemoveFieldReferences = shippingAddressMappedClass.getNulledOnRemoveFieldReferences(); + assertNotNull(nulledOnRemoveFieldReferences); + assertEquals(1, nulledOnRemoveFieldReferences.size()); + + nextEntry = nulledOnRemoveFieldReferences.entrySet().iterator().next(); + nextKey = nextEntry.getKey(); + assertNotNull(nextKey); + assertTrue(nextKey instanceof MappedFieldPerceroObject); + assertEquals("issuerAddress", nextKey.getField().getName()); + assertNotNull(nextKey.getReverseMappedField()); + + nextValue = nextEntry.getValue(); + assertNotNull(nextKey); + assertTrue(nextValue instanceof MappedFieldPerceroObject); + assertEquals("countryPermit", nextValue.getField().getName()); + assertNotNull(nextValue.getReverseMappedField()); + + assertSame(postalAddressMappedClass, shippingAddressMappedClass.parentMappedClass); + assertTrue(postalAddressMappedClass.getChildMappedClasses().contains(shippingAddressMappedClass)); + + // Checking inheritance. + for(MappedClass mc : mcm.getAllMappedClasses()) { + for(MappedClass childClass : mc.getChildMappedClasses()) { + assertTrue(mc.toManyFields.size() <= childClass.toManyFields.size()); + for(MappedField nextToManyMappedField : mc.toManyFields) { + boolean matchFound = false; + for(MappedField nextToManyMappedField2 : childClass.toOneFields) { + if (nextToManyMappedField.getField().equals(nextToManyMappedField2.getField())) { + matchFound = true; + assertSame(nextToManyMappedField.getReverseMappedField(), nextToManyMappedField2.getReverseMappedField()); + break; + } + } + + assertTrue(matchFound); + } + assertTrue(mc.toOneFields.size() <= childClass.toOneFields.size()); + for(MappedField nextToOneMappedField : mc.toOneFields) { + boolean matchFound = false; + for(MappedField nextToOneMappedField2 : childClass.toOneFields) { + if (nextToOneMappedField.getField().equals(nextToOneMappedField2.getField())) { + matchFound = true; + assertSame(nextToOneMappedField.getReverseMappedField(), nextToOneMappedField2.getReverseMappedField()); + break; + } + } + + assertTrue(matchFound); + } + + assertEquals(shippingAddressMappedClass.externalizableFields.size(), postalAddressMappedClass.externalizableFields.size()); + for(MappedField nextExternalizableField : postalAddressMappedClass.externalizableFields) { + boolean matchFound = false; + for(MappedField nextExternalizableField2 : shippingAddressMappedClass.externalizableFields) { + if (nextExternalizableField.getField().equals(nextExternalizableField2.getField())) { + matchFound = true; + assertSame(nextExternalizableField.getReverseMappedField(), nextExternalizableField2.getReverseMappedField()); + break; + } + } + + assertTrue(matchFound); + } + + assertEquals(shippingAddressMappedClass.propertyFields.size(), postalAddressMappedClass.propertyFields.size()); + for(MappedField nextPropertyField : postalAddressMappedClass.propertyFields) { + boolean matchFound = false; + for(MappedField nextPropertyField2 : shippingAddressMappedClass.propertyFields) { + if (nextPropertyField.getField().equals(nextPropertyField2.getField())) { + matchFound = true; + assertSame(nextPropertyField.getReverseMappedField(), nextPropertyField2.getReverseMappedField()); + break; + } + } + + assertTrue(matchFound); + } + } + } + } + + @Test + public void testHandleAnnotation_PropertyInterfaces() { + System.out.println("Not yet implemented"); + } + + @Test + public void testHandleAnnotation_PropertyInterface() { + System.out.println("Not yet implemented"); + } + + @Test + public void testHandleAnnotation_OneToOne() { + System.out.println("Not yet implemented"); + } + + @Test + public void testHandleAnnotation_ManyToOne() { + System.out.println("Not yet implemented"); + } + + @Test + public void testHandleAnnotation_OneToMany() { + System.out.println("Not yet implemented"); + } + + @Test + public void testHandleAnnotation_Id() { + System.out.println("Not yet implemented"); + } + + @Test + public void testHandleAnnotation_JoinColumn() { + System.out.println("Not yet implemented"); + } + + @Test + public void testHandleAnnotation_Column() { + System.out.println("Not yet implemented"); + } + + @Test + public void testHandleAnnotation_AccessRights() { + System.out.println("Not yet implemented"); + } +} diff --git a/src/test/java/com/percero/agents/sync/services/TestDaoDataProvider.java b/src/test/java/com/percero/agents/sync/services/TestDaoDataProvider.java new file mode 100644 index 0000000..e3f386e --- /dev/null +++ b/src/test/java/com/percero/agents/sync/services/TestDaoDataProvider.java @@ -0,0 +1,139 @@ +package com.percero.agents.sync.services; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestDaoDataProvider { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testFindByIdClassIDPairString() { + System.out.println("Not yet implemented"); + } + + @Test + public void testFindByIdClassIDPairStringBoolean() { + System.out.println("Not yet implemented"); + } + + @Test + public void testFindByIdClassIDPairStringBooleanBoolean() { + System.out.println("Not yet implemented"); + } + + @Test + public void testRetrieveCachedObject() { + System.out.println("Not yet implemented"); + } + + @Test + public void testCreateFromJson() { + System.out.println("Not yet implemented"); + } + + @Test + public void testFindByIdsClassIDPairsString() { + System.out.println("Not yet implemented"); + } + + @Test + public void testFindByIdsClassIDPairsStringBoolean() { + System.out.println("Not yet implemented"); + } + + @Test + public void testFindByExample() { + System.out.println("Not yet implemented"); + } + + @Test + public void testCreateObject() { + System.out.println("Not yet implemented"); + } + + @Test + public void testPutObject() { + System.out.println("Not yet implemented"); + } + + @Test + public void testHandleUpdatedClassIdPair() { + System.out.println("Not yet implemented"); + } + + @Test + public void testFindPerceroObjectInList() { + System.out.println("Not yet implemented"); + } + + @Test + public void testDeleteObject() { + System.out.println("Not yet implemented"); + } + + @Test + public void testGetChangedMappedFieldsIPerceroObject() { + System.out.println("Not yet implemented"); + } + + @Test + public void testGetChangedMappedFieldsIPerceroObjectBoolean() { + System.out.println("Not yet implemented"); + } + + @Test + public void testGetChangedMappedFieldsIPerceroObjectIPerceroObjectBoolean() { + System.out.println("Not yet implemented"); + } + + @Test + public void testFindAllRelatedObjects() { + System.out.println("Not yet implemented"); + } + + @Test + public void testIsMappedFieldInChangedFields() { + System.out.println("Not yet implemented"); + } + + @Test + public void testPopulateToManyRelationships() { + System.out.println("Not yet implemented"); + } + + @Test + public void testOverwriteToManyRelationships() { + System.out.println("Not yet implemented"); + } + + @Test + public void testPopulateToOneRelationships() { + System.out.println("Not yet implemented"); + } + + @Test + public void testOverwriteToOneRelationships() { + System.out.println("Not yet implemented"); + } + +} diff --git a/src/test/java/com/percero/agents/sync/services/TestSyncAgentService.java b/src/test/java/com/percero/agents/sync/services/TestSyncAgentService.java new file mode 100644 index 0000000..88d6683 --- /dev/null +++ b/src/test/java/com/percero/agents/sync/services/TestSyncAgentService.java @@ -0,0 +1,92 @@ +package com.percero.agents.sync.services; + +import static org.junit.Assert.assertTrue; + +import java.util.Collection; +import java.util.HashSet; + +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.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.percero.agents.sync.access.IAccessManager; +import com.percero.agents.sync.vo.ClassIDPair; +import com.percero.example.Person; +import com.percero.framework.vo.IPerceroObject; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:spring/percero-spring-config.xml" }) +public class TestSyncAgentService { + +// @Autowired +// SyncAgentService syncAgentService; + + SyncAgentService mockService = null; + IDataProvider dataProvider = null; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + mockService = Mockito.mock(SyncAgentService.class); + + mockService.accessManager = Mockito.mock(IAccessManager.class); + Mockito.when(mockService.accessManager.getClientUserId(Mockito.anyString())).thenReturn("USER_ID"); + + mockService.dataProviderManager = Mockito.mock(IDataProviderManager.class); + dataProvider = Mockito.mock(IDataProvider.class); + Mockito.when(mockService.dataProviderManager.getDataProviderByName(Mockito.anyString())).thenReturn(dataProvider); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testSystemDeleteObjectClassIDPairStringBoolean() throws Exception { + Mockito.when(mockService.systemDeleteObject(Mockito.any(ClassIDPair.class), Mockito.anyString(), Mockito.anyBoolean())).thenCallRealMethod(); + mockService.systemDeleteObject(new ClassIDPair("1", Person.class.getCanonicalName()), "clientId", true); + Mockito.verify(mockService, Mockito.times(1)).systemDeleteObject(Mockito.any(ClassIDPair.class), Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyCollection()); + } + + @Test + public void testSystemDeleteObjectClassIDPairStringBooleanCollectionOfClassIDPair() throws Exception { + Mockito.when(mockService.systemDeleteObject(Mockito.any(ClassIDPair.class), Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyCollection())).thenCallRealMethod(); + boolean result = mockService.systemDeleteObject(null, "clientId", true, null); + + Collection deletedObjects = new HashSet(1); + deletedObjects.add(new ClassIDPair("1", Person.class.getCanonicalName())); + result = mockService.systemDeleteObject(new ClassIDPair("1", Person.class.getCanonicalName()), "clientId", true, deletedObjects); + assertTrue(result); + + // If object does NOT exist, then it should just be ignored. + deletedObjects.clear(); + Mockito.when(dataProvider.findById(Mockito.any(ClassIDPair.class), Mockito.anyString())).thenReturn(null); + result = mockService.systemDeleteObject(new ClassIDPair("1", Person.class.getCanonicalName()), "clientId", true, deletedObjects); + assertTrue(result); + + Person person = new Person(); + Mockito.when(dataProvider.findById(Mockito.any(ClassIDPair.class), Mockito.anyString())).thenReturn(person); + + result = mockService.systemDeleteObject(new ClassIDPair("1", Person.class.getCanonicalName()), "clientId", true, deletedObjects); + assertTrue(result); + assertTrue(deletedObjects.contains(new ClassIDPair("1", Person.class.getCanonicalName()))); + } + + @Test + public void test_handleUpdateObject_ChangedFields() { + System.out.println("Not yet implemented"); + } +} diff --git a/src/test/java/com/percero/amqp/TestRabbitMQPushSyncHelper.java b/src/test/java/com/percero/amqp/TestRabbitMQPushSyncHelper.java new file mode 100644 index 0000000..66ca5e7 --- /dev/null +++ b/src/test/java/com/percero/amqp/TestRabbitMQPushSyncHelper.java @@ -0,0 +1,409 @@ +package com.percero.amqp; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.codehaus.jackson.map.ObjectMapper; +import org.joda.time.Duration; +import org.joda.time.Instant; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.amqp.core.Message; + +import com.google.gson.JsonSyntaxException; +import com.percero.agents.sync.access.IAccessManager; +import com.percero.agents.sync.datastore.ICacheDataStore; + +public class TestRabbitMQPushSyncHelper { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + RabbitMQPushSyncHelper pushSyncHelper; + final String jsonMessages = "[{\"memory\":21920,\"messages\":0,\"messages_details\":{\"rate\":0.0},\"messages_ready\":0,\"messages_ready_details\":{\"rate\":0.0},\"messages_unacknowledged\":0,\"messages_unacknowledged_details\":{\"rate\":0.0},\"idle_since\":\"2016-03-11 0:33:28\",\"consumer_utilisation\":null,\"policy\":null,\"exclusive_consumer_tag\":null,\"consumers\":2,\"recoverable_slaves\":null,\"state\":\"running\",\"messages_ram\":0,\"messages_ready_ram\":0,\"messages_unacknowledged_ram\":0,\"messages_persistent\":0,\"message_bytes\":0,\"message_bytes_ready\":0,\"message_bytes_unacknowledged\":0,\"message_bytes_ram\":0,\"message_bytes_persistent\":0,\"head_message_timestamp\":null,\"disk_reads\":0,\"disk_writes\":0,\"backing_queue_status\":{\"mode\":\"default\",\"q1\":0,\"q2\":0,\"delta\":[\"delta\",\"undefined\",0,\"undefined\"],\"q3\":0,\"q4\":0,\"len\":0,\"target_ram_count\":\"infinity\",\"next_seq_id\":0,\"avg_ingress_rate\":0.0,\"avg_egress_rate\":0.0,\"avg_ack_ingress_rate\":0.0,\"avg_ack_egress_rate\":0.0},\"name\":\"17\",\"vhost\":\"/\",\"durable\":true,\"auto_delete\":false,\"exclusive\":false,\"arguments\":{},\"node\":\"testnode\"},{\"memory\":21920,\"messages\":0,\"messages_details\":{\"rate\":0.0},\"messages_ready\":0,\"messages_ready_details\":{\"rate\":0.0},\"messages_unacknowledged\":0,\"messages_unacknowledged_details\":{\"rate\":0.0},\"idle_since\":\"2016-03-11 0:33:28\",\"consumer_utilisation\":null,\"policy\":null,\"exclusive_consumer_tag\":null,\"consumers\":0,\"recoverable_slaves\":null,\"state\":\"running\",\"messages_ram\":0,\"messages_ready_ram\":0,\"messages_unacknowledged_ram\":0,\"messages_persistent\":0,\"message_bytes\":0,\"message_bytes_ready\":0,\"message_bytes_unacknowledged\":0,\"message_bytes_ram\":0,\"message_bytes_persistent\":0,\"head_message_timestamp\":null,\"disk_reads\":0,\"disk_writes\":0,\"backing_queue_status\":{\"mode\":\"default\",\"q1\":0,\"q2\":0,\"delta\":[\"delta\",\"undefined\",0,\"undefined\"],\"q3\":0,\"q4\":0,\"len\":0,\"target_ram_count\":\"infinity\",\"next_seq_id\":0,\"avg_ingress_rate\":0.0,\"avg_egress_rate\":0.0,\"avg_ack_ingress_rate\":0.0,\"avg_ack_egress_rate\":0.0},\"name\":\"41\",\"vhost\":\"/\",\"durable\":true,\"auto_delete\":false,\"exclusive\":false,\"arguments\":{},\"node\":\"testnode\"},{\"memory\":21920,\"messages\":0,\"messages_details\":{\"rate\":0.0},\"messages_ready\":0,\"messages_ready_details\":{\"rate\":0.0},\"messages_unacknowledged\":0,\"messages_unacknowledged_details\":{\"rate\":0.0},\"idle_since\":\"2016-03-11 0:33:27\",\"consumer_utilisation\":null,\"policy\":null,\"exclusive_consumer_tag\":null,\"consumers\":0,\"recoverable_slaves\":null,\"state\":\"running\",\"messages_ram\":0,\"messages_ready_ram\":0,\"messages_unacknowledged_ram\":0,\"messages_persistent\":0,\"message_bytes\":0,\"message_bytes_ready\":0,\"message_bytes_unacknowledged\":0,\"message_bytes_ram\":0,\"message_bytes_persistent\":0,\"head_message_timestamp\":null,\"disk_reads\":0,\"disk_writes\":0,\"backing_queue_status\":{\"mode\":\"default\",\"q1\":0,\"q2\":0,\"delta\":[\"delta\",\"undefined\",0,\"undefined\"],\"q3\":0,\"q4\":0,\"len\":0,\"target_ram_count\":\"infinity\",\"next_seq_id\":0,\"avg_ingress_rate\":0.0,\"avg_egress_rate\":0.0,\"avg_ack_ingress_rate\":0.0,\"avg_ack_egress_rate\":0.0},\"name\":\"42\",\"vhost\":\"/\",\"durable\":true,\"auto_delete\":false,\"exclusive\":false,\"arguments\":{},\"node\":\"testnode\"},{\"memory\":21848,\"message_stats\":{\"ack\":1361,\"ack_details\":{\"rate\":0.0},\"deliver\":1361,\"deliver_details\":{\"rate\":0.0},\"deliver_get\":1361,\"deliver_get_details\":{\"rate\":0.0},\"publish\":1362,\"publish_details\":{\"rate\":0.0}},\"messages\":1,\"messages_details\":{\"rate\":0.0},\"messages_ready\":1,\"messages_ready_details\":{\"rate\":0.0},\"messages_unacknowledged\":0,\"messages_unacknowledged_details\":{\"rate\":0.0},\"idle_since\":\"2016-03-11 0:33:31\",\"consumer_utilisation\":null,\"policy\":null,\"exclusive_consumer_tag\":null,\"consumers\":0,\"recoverable_slaves\":null,\"state\":\"running\",\"messages_ram\":1,\"messages_ready_ram\":1,\"messages_unacknowledged_ram\":0,\"messages_persistent\":0,\"message_bytes\":191,\"message_bytes_ready\":191,\"message_bytes_unacknowledged\":0,\"message_bytes_ram\":191,\"message_bytes_persistent\":0,\"head_message_timestamp\":null,\"disk_reads\":0,\"disk_writes\":0,\"backing_queue_status\":{\"mode\":\"default\",\"q1\":0,\"q2\":0,\"delta\":[\"delta\",\"undefined\",0,\"undefined\"],\"q3\":0,\"q4\":1,\"len\":1,\"target_ram_count\":\"infinity\",\"next_seq_id\":1362,\"avg_ingress_rate\":0.0005576266319825132,\"avg_egress_rate\":6.819506093702665e-109,\"avg_ack_ingress_rate\":6.819506093702665e-109,\"avg_ack_egress_rate\":6.824693279456112e-109},\"name\":\"aa275b1eeb0f340a6430180c9a703795\",\"vhost\":\"/\",\"durable\":false,\"auto_delete\":false,\"exclusive\":false,\"arguments\":{},\"node\":\"testnode\"}]"; + + @Before + public void setUp() throws Exception { + pushSyncHelper = Mockito.mock(RabbitMQPushSyncHelper.class); + pushSyncHelper.template = Mockito.mock(AmqpTemplate.class); + pushSyncHelper.objectMapper = new ObjectMapper(); + pushSyncHelper.accessManager = Mockito.mock(IAccessManager.class); + pushSyncHelper.cacheDataStore = Mockito.mock(ICacheDataStore.class); + } + + @After + public void tearDown() throws Exception { + } + + @SuppressWarnings("unchecked") + @Test + public void testValidateQueues() { + + // Should not run when it is currently being run. + pushSyncHelper.validatingQueues = true; + boolean result = pushSyncHelper.validateQueues(); + assertFalse(result); + pushSyncHelper.validatingQueues = false; + + // Setup QueueProperties to check + final Set queuePropertiesSet = new HashSet(); + + QueueProperties queueProperties = new QueueProperties(); + queueProperties.setQueueName("QUEUE_1"); + queuePropertiesSet.add(queueProperties); + QueueProperties queueProperties2 = new QueueProperties(); + queueProperties2.setQueueName("QUEUE_2"); + queuePropertiesSet.add(queueProperties2); + + Mockito.when(pushSyncHelper.validateQueues()).thenCallRealMethod(); + try { + Mockito.when(pushSyncHelper.retrieveQueueProperties(Mockito.anyBoolean())) + .thenAnswer(new Answer>() { + @Override + public Set answer(InvocationOnMock invocation) throws Throwable { + return queuePropertiesSet; + } + }); + } catch (JsonSyntaxException | IOException e) { + fail(e.getMessage()); + } + + Set validClients = new HashSet(); + try { + Mockito.when(pushSyncHelper.accessManager.validateClients(Mockito.anyCollection())).thenReturn(validClients); + } catch (Exception e) { + fail(e.getMessage()); + } + + // If queue is a valid client, then do NOT log them out. + try { + Mockito.verify(pushSyncHelper.accessManager, Mockito.never()).logoutClient(Mockito.anyString(), Mockito.anyBoolean()); + } catch (Exception e) { + fail(e.getMessage()); + } + + validClients.add("QUEUE_1"); + validClients.add("QUEUE_2"); + Mockito.when(pushSyncHelper.checkQueueForDeletion(Mockito.any(QueueProperties.class))).thenReturn(true).thenReturn(false); + Mockito.when(pushSyncHelper.checkQueueForLogout(Mockito.any(QueueProperties.class))).thenReturn(true); + + result = pushSyncHelper.validateQueues(); + assertTrue(result); + // Make sure we finish cleanly. + assertFalse(pushSyncHelper.validatingQueues); + + Mockito.verify(pushSyncHelper, Mockito.times(2)).checkQueueForDeletion(Mockito.any(QueueProperties.class)); + Mockito.verify(pushSyncHelper, Mockito.times(1)).checkQueueForLogout(Mockito.any(QueueProperties.class)); + Mockito.verify(pushSyncHelper, Mockito.times(1)).deleteQueue(Mockito.anyString()); + try { + Mockito.verify(pushSyncHelper.accessManager, Mockito.never()).logoutClient(Mockito.anyString(), Mockito.anyBoolean()); + } catch (Exception e) { + fail(e.getMessage()); + } + + // If queue is NOT a valid client, then DO log them out. + validClients.clear(); + Mockito.when(pushSyncHelper.checkQueueForDeletion(Mockito.any(QueueProperties.class))).thenReturn(true).thenReturn(false); + Mockito.when(pushSyncHelper.checkQueueForLogout(Mockito.any(QueueProperties.class))).thenReturn(true); + result = pushSyncHelper.validateQueues(); + assertTrue(result); + // Make sure we finish cleanly. + assertFalse(pushSyncHelper.validatingQueues); + + Mockito.verify(pushSyncHelper, Mockito.times(4)).checkQueueForDeletion(Mockito.any(QueueProperties.class)); + Mockito.verify(pushSyncHelper, Mockito.times(2)).checkQueueForLogout(Mockito.any(QueueProperties.class)); + Mockito.verify(pushSyncHelper, Mockito.times(2)).deleteQueue(Mockito.anyString()); + try { + Mockito.verify(pushSyncHelper.accessManager, Mockito.times(1)).logoutClient(Mockito.anyString(), Mockito.anyBoolean()); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + @Test + public void testCheckQueueForDeletion() { + String queueName = "QUEUE"; + int numMessages = 0; + int numConsumers = 0; + Instant dateTimeIdleSince = Instant.now().minus(Duration.standardDays(7).getMillis()); + boolean isEolClientsMember = false; + + Mockito.when(pushSyncHelper.checkQueueForDeletion(Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.any(Instant.class), Mockito.anyBoolean())).thenCallRealMethod(); + Mockito.when(pushSyncHelper.queueHasTimedOut(Mockito.anyString(), Mockito.any(Instant.class))).thenCallRealMethod(); + + // If queueName is in QueueNames, then false + pushSyncHelper.queueNames = new HashSet<>(); + pushSyncHelper.queueNames.add(queueName); + boolean result = pushSyncHelper.checkQueueForDeletion(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertFalse(result); + + // If no consumers and IS EOL client with no messages, then true + // if isEolClientsMember AND (numMessages <= 0 OR numConsumers == 0), then true + pushSyncHelper.queueNames = new HashSet<>(); + isEolClientsMember = true; + numConsumers = 0; + numMessages = 5; + result = pushSyncHelper.checkQueueForDeletion(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertTrue(result); + + numConsumers = 2; + numMessages = 0; + result = pushSyncHelper.checkQueueForDeletion(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertTrue(result); + + numConsumers = 0; + numMessages = 0; + result = pushSyncHelper.checkQueueForDeletion(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertTrue(result); + + // If NOT EOL Client Member AND Consumers, then false + isEolClientsMember = false; + numConsumers = 5; + result = pushSyncHelper.checkQueueForDeletion(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertFalse(result); + + // If numConsumers == 0 AND numMessages > 0 AND queue has NOT timed out, then false + isEolClientsMember = false; + numMessages = 12; + numConsumers = 0; + dateTimeIdleSince = Instant.now(); + pushSyncHelper.rabbitQueueTimeout = 50 * 1000; // 50 s + result = pushSyncHelper.checkQueueForDeletion(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertFalse(result); + + // If numConsumers == 0 AND numMessages > 0 AND queue HAS timed out AND queue contains NO EOL message, then false + isEolClientsMember = false; + numMessages = 12; + numConsumers = 0; + dateTimeIdleSince = Instant.now().minus(Duration.standardDays(7).getMillis()); + pushSyncHelper.rabbitQueueTimeout = 500; // 500 ms + result = pushSyncHelper.checkQueueForDeletion(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertFalse(result); + + // If numConsumers == 0 AND numMessages > 0 AND queue HAS timed out AND queue contains EOL message, then true + isEolClientsMember = false; + numMessages = 12; + numConsumers = 0; + Message eolMessage = new Message("{\"EOL\": true}".getBytes(), null); + Mockito.when(pushSyncHelper.template.receive(Mockito.anyString())).thenReturn(eolMessage); + result = pushSyncHelper.checkQueueForDeletion(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertTrue(result); + + // Valid messages should be requeued. + isEolClientsMember = false; + numMessages = 12; + numConsumers = 0; + Message notEolMessage = new Message("{\"OTHER\": true}".getBytes(), null); + Mockito.when(pushSyncHelper.template.receive(Mockito.anyString())).thenReturn(notEolMessage).thenReturn(null); + Mockito.verify(pushSyncHelper.template, Mockito.never()).send(Mockito.anyString(), Mockito.any(Message.class)); + result = pushSyncHelper.checkQueueForDeletion(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + Mockito.verify(pushSyncHelper.template, Mockito.atLeastOnce()).send(Mockito.anyString(), Mockito.any(Message.class)); + assertFalse(result); + } + + @Test + public void testCheckQueueForLogout() { + String queueName = "QUEUE"; + int numMessages = 0; + int numConsumers = 0; + Instant dateTimeIdleSince = Instant.now().minus(Duration.standardDays(7).getMillis()); + boolean isEolClientsMember = false; + + Mockito.when(pushSyncHelper.checkQueueForLogout(Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.any(Instant.class), Mockito.anyBoolean())).thenCallRealMethod(); + Mockito.when(pushSyncHelper.queueHasTimedOut(Mockito.anyString(), Mockito.any(Instant.class))).thenCallRealMethod(); + + // If queueName is in QueueNames, then false + pushSyncHelper.queueNames = new HashSet<>(); + pushSyncHelper.queueNames.add(queueName); + boolean result = pushSyncHelper.checkQueueForLogout(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertFalse(result); + + // If EOL Client Member, then false + pushSyncHelper.queueNames = new HashSet<>(); + isEolClientsMember = true; + result = pushSyncHelper.checkQueueForLogout(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertFalse(result); + + // If NOT EOL Client Member AND numConsumers > 0, then false + pushSyncHelper.queueNames = new HashSet<>(); + isEolClientsMember = false; + numConsumers = 5; + result = pushSyncHelper.checkQueueForLogout(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertFalse(result); + + // If NOT EOL Client Member AND numConsumers <= 0 AND dateTimeIdleSince IS NULL, then false + pushSyncHelper.queueNames = new HashSet<>(); + isEolClientsMember = false; + numConsumers = 0; + dateTimeIdleSince = null; + result = pushSyncHelper.checkQueueForLogout(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertFalse(result); + + // If NOT EOL Client Member AND numConsumers <= 0 AND time difference > rabbitQueueTimeout, then true + pushSyncHelper.queueNames = new HashSet<>(); + isEolClientsMember = false; + numConsumers = 0; + dateTimeIdleSince = Instant.now().minus(Duration.standardDays(7).getMillis()); + pushSyncHelper.rabbitQueueTimeout = 500; // 500 ms + result = pushSyncHelper.checkQueueForLogout(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertTrue(result); + + // If NOT EOL Client Member AND numConsumers <= 0 AND time difference < rabbitQueueTimeout, then false + pushSyncHelper.queueNames = new HashSet<>(); + isEolClientsMember = false; + numConsumers = 0; + dateTimeIdleSince = Instant.now(); + pushSyncHelper.rabbitQueueTimeout = 50 * 1000; // 50 s + result = pushSyncHelper.checkQueueForLogout(queueName, numMessages, numConsumers, dateTimeIdleSince, isEolClientsMember); + assertFalse(result); + } + + @Test + public void testQueueHasTimedOut() { + String queueName = "QUEUE"; + Instant dateTimeIdleSince = Instant.now().minus(Duration.standardDays(7).getMillis()); + + Mockito.when(pushSyncHelper.queueHasTimedOut(Mockito.anyString(), Mockito.any(Instant.class))).thenCallRealMethod(); + + // If queueName is in QueueNames, then false + pushSyncHelper.queueNames = new HashSet<>(); + pushSyncHelper.queueNames.add(queueName); + boolean result = pushSyncHelper.queueHasTimedOut(queueName, dateTimeIdleSince); + assertFalse(result); + + // If time difference > rabbitQueueTimeout, then true + pushSyncHelper.queueNames = new HashSet<>(); + dateTimeIdleSince = Instant.now().minus(Duration.standardDays(7).getMillis()); + pushSyncHelper.rabbitQueueTimeout = 500; // 500 ms + result = pushSyncHelper.queueHasTimedOut(queueName, dateTimeIdleSince); + assertTrue(result); + + // If time difference < rabbitQueueTimeout, then false + pushSyncHelper.queueNames = new HashSet<>(); + dateTimeIdleSince = Instant.now(); + pushSyncHelper.rabbitQueueTimeout = 50 * 1000; // 50 s + result = pushSyncHelper.queueHasTimedOut(queueName, dateTimeIdleSince); + assertFalse(result); + } + + @Test + public void testRetrieveQueuesJsonListAsString() { + + try { + Mockito.when(pushSyncHelper.retrieveQueuesJsonListAsString()).thenCallRealMethod(); + + // If NO rabbit host, then should return an empty string + pushSyncHelper.rabbitHost = null; + String result = pushSyncHelper.retrieveQueuesJsonListAsString(); + assertEquals("", result); + + pushSyncHelper.rabbitHost = ""; + result = pushSyncHelper.retrieveQueuesJsonListAsString(); + assertEquals("", result); + + pushSyncHelper.rabbitHost = "localhost"; + pushSyncHelper.rabbitAdminPort = 15672; + pushSyncHelper.rabbitLogin = "guest"; + pushSyncHelper.rabbitPassword = "guest"; + + final String uri = "http://" + pushSyncHelper.rabbitHost + ":" + pushSyncHelper.rabbitAdminPort + "/api/queues/"; + Mockito.when(pushSyncHelper.issueHttpCall(Mockito.anyString(), Mockito.any(AuthScope.class), Mockito.any(Credentials.class))).then(new Answer() { + @Override + public String answer(InvocationOnMock invocation) throws Throwable { + if (uri.equals(invocation.getArguments()[0])) { + return jsonMessages; + } + else { + return ""; + } + } + }); + + String jsonList = pushSyncHelper.retrieveQueuesJsonListAsString(); + + assertEquals(jsonMessages, jsonList); + } catch (IOException e) { + fail(e.getMessage()); + } + + } + + @Test + public void testRetrieveQueueProperties() { + // TODO: Get a valid Rabbit Message JSON response (by setting rabbitHost and port), then use that as seed data for this method. + pushSyncHelper.rabbitHost = "localhost"; + pushSyncHelper.rabbitAdminPort = 15672; + pushSyncHelper.rabbitLogin = "guest"; + pushSyncHelper.rabbitPassword = "guest"; + pushSyncHelper.queueNames = new HashSet(); + pushSyncHelper.queueNames.add("41"); + + Mockito.when(pushSyncHelper.cacheDataStore.getSetIsMember(Mockito.anyString(), Mockito.anyObject())).thenAnswer(new Answer() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + if("42".equals(invocation.getArguments()[1])) { + return true; + } + else { + return false; + } + } + }); + + try { + Mockito.when(pushSyncHelper.retrieveQueuesJsonListAsString()).thenReturn(jsonMessages); + Mockito.when(pushSyncHelper.retrieveQueueProperties(Mockito.anyBoolean())).thenCallRealMethod(); + Set queueProperties = pushSyncHelper.retrieveQueueProperties(false); + assertNotNull(queueProperties); + // There are 4 queues in the JSON, but we do NOT want the queue named "41" since that has been registered as a "system" queue. + assertEquals(3, queueProperties.size()); + + for(QueueProperties qp : queueProperties) { + if ("42".equals(qp.getQueueName())) { + assertEquals(0, qp.getNumConsumers()); + assertEquals(0, qp.getNumMessages()); + assertTrue(qp.isEolClientsMember()); + assertEquals(new Instant(1457656407000l), qp.getDateTimeIdleSince()); + } + else if ("17".equals(qp.getQueueName())) { + assertEquals(2, qp.getNumConsumers()); + assertEquals(0, qp.getNumMessages()); + assertFalse(qp.isEolClientsMember()); + assertEquals(new Instant(1457656408000l), qp.getDateTimeIdleSince()); + } + else if ("aa275b1eeb0f340a6430180c9a703795".equals(qp.getQueueName())) { + assertEquals(0, qp.getNumConsumers()); + assertEquals(1, qp.getNumMessages()); + assertFalse(qp.isEolClientsMember()); + assertEquals(new Instant(1457656411000l), qp.getDateTimeIdleSince()); + } + } + + } catch (IOException e) { + fail(e.getMessage()); + } + + } + +} diff --git a/src/test/java/com/percero/client/AStackClient.java b/src/test/java/com/percero/client/AStackClient.java index f9c39e1..2eb92bd 100644 --- a/src/test/java/com/percero/client/AStackClient.java +++ b/src/test/java/com/percero/client/AStackClient.java @@ -1,14 +1,10 @@ package com.percero.client; +import java.util.UUID; + 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 @@ -21,10 +17,8 @@ public class AStackClient { */ private AStackRPCService rpcService; private String clientId = UUID.randomUUID().toString(); - private ConnectionFactory amqpConnectionFactory; - public AStackClient(AStackRPCService rpcService, ConnectionFactory amqpConnectionFactory){ + public AStackClient(AStackRPCService rpcService){ this.rpcService = rpcService; - this.amqpConnectionFactory = amqpConnectionFactory; } /** @@ -40,35 +34,7 @@ public boolean authenticateAnonymously(){ 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 index 18f4006..2982c9f 100644 --- a/src/test/java/com/percero/client/AStackClientFactory.java +++ b/src/test/java/com/percero/client/AStackClientFactory.java @@ -1,6 +1,5 @@ package com.percero.client; -import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -13,10 +12,7 @@ public class AStackClientFactory { @Autowired AStackRPCService rpcService; - @Autowired - ConnectionFactory connectionFactory; - public AStackClient getClient(){ - return new AStackClient(rpcService, connectionFactory); + return new AStackClient(rpcService); } } diff --git a/src/test/java/com/percero/client/AStackClientTest.java b/src/test/java/com/percero/client/AStackClientTest.java index 517a89c..0adcd83 100644 --- a/src/test/java/com/percero/client/AStackClientTest.java +++ b/src/test/java/com/percero/client/AStackClientTest.java @@ -1,14 +1,16 @@ package com.percero.client; -import com.percero.agents.sync.jobs.UpdateTablePoller; -import com.percero.test.utils.CleanerUtil; +import static org.junit.Assert.assertTrue; + 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.*; + +import com.percero.agents.sync.jobs.UpdateTablePoller; +import com.percero.test.utils.CleanerUtil; /** * Created by jonnysamps on 9/14/15. @@ -31,7 +33,7 @@ public void before(){ poller.enabled = false; cleanerUtil.cleanAll(); } - + @Test public void authenticateAnonymously(){ AStackClient client = clientFactory.getClient(); diff --git a/src/test/java/com/percero/client/AStackRPCService.java b/src/test/java/com/percero/client/AStackRPCService.java index 0818695..0a5831e 100644 --- a/src/test/java/com/percero/client/AStackRPCService.java +++ b/src/test/java/com/percero/client/AStackRPCService.java @@ -1,11 +1,12 @@ 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; +import com.percero.agents.auth.services.AuthService2; +import com.percero.agents.auth.vo.AuthenticationRequest; +import com.percero.agents.auth.vo.AuthenticationResponse; + /** * Main interface for communicating to the backend through AMQP * Created by jonnysamps on 9/13/15. @@ -14,10 +15,11 @@ public class AStackRPCService { @Autowired - AmqpTemplate amqpTemplate; + AuthService2 authService2; public AuthenticationResponse authenticate(AuthenticationRequest request){ - return (AuthenticationResponse) amqpTemplate.convertSendAndReceive("authenticate", request); + AuthenticationResponse response = (AuthenticationResponse) authService2.authenticate(request); + return response; } } diff --git a/src/test/java/com/percero/example/Country.java b/src/test/java/com/percero/example/Country.java new file mode 100644 index 0000000..f001795 --- /dev/null +++ b/src/test/java/com/percero/example/Country.java @@ -0,0 +1,11 @@ +package com.percero.example; + +import javax.persistence.Entity; + +import com.percero.example.mo_super._Super_Country; + +@Entity(name="Country") +public class Country extends _Super_Country +{ + +} diff --git a/src/test/java/com/percero/example/CountryPermit.java b/src/test/java/com/percero/example/CountryPermit.java new file mode 100644 index 0000000..73375e5 --- /dev/null +++ b/src/test/java/com/percero/example/CountryPermit.java @@ -0,0 +1,11 @@ +package com.percero.example; + +import javax.persistence.Entity; + +import com.percero.example.mo_super._Super_CountryPermit; + +@Entity(name="CountryPermit") +public class CountryPermit extends _Super_CountryPermit +{ + +} diff --git a/src/test/java/com/percero/example/ExampleManifest.java b/src/test/java/com/percero/example/ExampleManifest.java index a9cf5b9..0dfd43a 100644 --- a/src/test/java/com/percero/example/ExampleManifest.java +++ b/src/test/java/com/percero/example/ExampleManifest.java @@ -22,6 +22,13 @@ public List getClassList() { classList.add(PersonRole.class); classList.add(Email.class); classList.add(Block.class); + + classList.add(Country.class); + classList.add(CountryPermit.class); + classList.add(PermitDocument.class); + classList.add(PermitLine.class); + classList.add(PostalAddress.class); + classList.add(ShippingAddress.class); } return classList; } @@ -35,6 +42,13 @@ public List getObjectList() { objectList.add(new PersonRole()); objectList.add(new Email()); objectList.add(new Block()); + + objectList.add(new Country()); + objectList.add(new CountryPermit()); + objectList.add(new PermitDocument()); + objectList.add(new PermitLine()); + objectList.add(new PostalAddress()); + objectList.add(new ShippingAddress()); } return objectList; } @@ -48,6 +62,13 @@ public Map getUuidMap() { uuidMap.put("2", PersonRole.class); uuidMap.put("3", Email.class); uuidMap.put("4", Block.class); + + uuidMap.put("5", Country.class); + uuidMap.put("6", CountryPermit.class); + uuidMap.put("7", PermitDocument.class); + uuidMap.put("8", PermitLine.class); + uuidMap.put("9", PostalAddress.class); + uuidMap.put("10", ShippingAddress.class); } return uuidMap; } diff --git a/src/test/java/com/percero/example/PermitDocument.java b/src/test/java/com/percero/example/PermitDocument.java new file mode 100644 index 0000000..0be9de5 --- /dev/null +++ b/src/test/java/com/percero/example/PermitDocument.java @@ -0,0 +1,11 @@ +package com.percero.example; + +import javax.persistence.Entity; + +import com.percero.example.mo_super._Super_PermitDocument; + +@Entity(name="PermitDocument") +public class PermitDocument extends _Super_PermitDocument +{ + +} diff --git a/src/test/java/com/percero/example/PermitLine.java b/src/test/java/com/percero/example/PermitLine.java new file mode 100644 index 0000000..58c0d0d --- /dev/null +++ b/src/test/java/com/percero/example/PermitLine.java @@ -0,0 +1,11 @@ +package com.percero.example; + +import javax.persistence.Entity; + +import com.percero.example.mo_super._Super_PermitLine; + +@Entity(name="PermitLine") +public class PermitLine extends _Super_PermitLine +{ + +} diff --git a/src/test/java/com/percero/example/Person.java b/src/test/java/com/percero/example/Person.java index 1dccf05..dd13d44 100644 --- a/src/test/java/com/percero/example/Person.java +++ b/src/test/java/com/percero/example/Person.java @@ -2,15 +2,21 @@ import com.google.gson.JsonObject; import com.percero.agents.auth.vo.IUserAnchor; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClass.MappedClassMethodPair; 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.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; @@ -134,6 +140,21 @@ public List getCircles() { public void setCircles(List value) { this.circles = value; } + + + + @JsonSerialize(using=BDOSerializer.class) + @JsonDeserialize(using=BDODeserializer.class) + @com.percero.agents.sync.metadata.annotations.Externalize + @OneToOne(fetch=FetchType.LAZY, mappedBy="person", cascade=javax.persistence.CascadeType.REMOVE) + private PersonDetail personDetail; + public PersonDetail getPersonDetail() { + return this.personDetail; + } + public void setPersonDetail(PersonDetail value) { + this.personDetail = value; + } + ////////////////////////////////////////////////////// // JSON @@ -265,6 +286,17 @@ public String retrieveJson(ObjectMapper objectMapper) { } objectJson += "]"; + // Target Relationships + objectJson += ",\"personDetail\":"; + if (getPersonDetail() == null) + objectJson += "null"; + else { + try { + objectJson += ((BaseDataObject) getPersonDetail()).toEmbeddedJson(); + } catch(Exception e) { + objectJson += "null"; + } + } return objectJson; @@ -281,9 +313,22 @@ protected void fromJson(JsonObject jsonObject) { setFirstName(JsonUtils.getJsonString(jsonObject, "firstName")); setLastName(com.percero.serial.JsonUtils.getJsonString(jsonObject, "lastName")); - this.personRoles = (List) JsonUtils.getJsonListPerceroObject(jsonObject, "personRoles"); + this.personRoles = (List) JsonUtils.getJsonListPerceroObject(jsonObject, "personRoles"); this.emails = (List) JsonUtils.getJsonListPerceroObject(jsonObject, "emails"); this.circles = (List) JsonUtils.getJsonListPerceroObject(jsonObject, "circles"); + + // Target Relationships + this.personDetail = JsonUtils.getJsonPerceroObject(jsonObject, "personDetail"); } + @Override + protected List getListSetters() { + List listSetters = super.getListSetters(); + + // Target Relationships + listSetters.add(MappedClass.getFieldSetters(CountryPermit.class, "personDetail")); + + return listSetters; + } + } diff --git a/src/test/java/com/percero/example/PersonDetail.java b/src/test/java/com/percero/example/PersonDetail.java new file mode 100644 index 0000000..f621545 --- /dev/null +++ b/src/test/java/com/percero/example/PersonDetail.java @@ -0,0 +1,144 @@ +package com.percero.example; + +import java.io.IOException; +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; + +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; + +import com.google.gson.JsonObject; +import com.percero.agents.auth.vo.IUserRole; +import com.percero.agents.sync.metadata.annotations.Externalize; +import com.percero.agents.sync.metadata.annotations.RelationshipInterface; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.serial.JsonUtils; + +@Entity +public class PersonDetail extends BaseDataObject implements Serializable +{ + ////////////////////////////////////////////////////// + // 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 String detail1; + public String getDetail1() { + return this.detail1; + } + public void setDetail1(String value) + { + this.detail1 = value; + } + + + ////////////////////////////////////////////////////// + // Source Relationships + ////////////////////////////////////////////////////// + @RelationshipInterface(entityInterfaceClass=IUserRole.class, sourceVarName="userAnchor") + @Externalize + @JoinColumn(name="person_ID") + @org.hibernate.annotations.ForeignKey(name="FK_User_user_TO_UserRole") + @OneToOne(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 += ",\"detail1\":"; + if (getDetail1() == null) + objectJson += "null"; + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson += objectMapper.writeValueAsString(getDetail1()); + } 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 + setDetail1(JsonUtils.getJsonString(jsonObject, "detail1")); + + // Source Relationships + this.person = JsonUtils.getJsonPerceroObject(jsonObject, "person"); + + // Target Relationships + } +} + diff --git a/src/test/java/com/percero/example/PostalAddress.java b/src/test/java/com/percero/example/PostalAddress.java new file mode 100644 index 0000000..811a892 --- /dev/null +++ b/src/test/java/com/percero/example/PostalAddress.java @@ -0,0 +1,11 @@ +package com.percero.example; + +import javax.persistence.Entity; + +import com.percero.example.mo_super._Super_PostalAddress; + +@Entity(name="PostalAddress") +public class PostalAddress extends _Super_PostalAddress +{ + +} diff --git a/src/test/java/com/percero/example/ShippingAddress.java b/src/test/java/com/percero/example/ShippingAddress.java new file mode 100644 index 0000000..586b4a5 --- /dev/null +++ b/src/test/java/com/percero/example/ShippingAddress.java @@ -0,0 +1,11 @@ +package com.percero.example; + +import javax.persistence.Entity; + +import com.percero.example.mo_super._Super_ShippingAddress; + +@Entity(name="ShippingAddress") +public class ShippingAddress extends _Super_ShippingAddress +{ + +} diff --git a/src/test/java/com/percero/example/mo_super/_Super_Country.java b/src/test/java/com/percero/example/mo_super/_Super_Country.java new file mode 100644 index 0000000..b079929 --- /dev/null +++ b/src/test/java/com/percero/example/mo_super/_Super_Country.java @@ -0,0 +1,196 @@ +package com.percero.example.mo_super; + +import java.io.IOException; +import java.io.Serializable; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; + +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; + +import com.google.gson.JsonObject; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClass.MappedClassMethodPair; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.example.CountryPermit; +import com.percero.example.PostalAddress; +import com.percero.serial.JsonUtils; + +@MappedSuperclass +@NamedQueries({ + @NamedQuery(name="updateQuery", query="sql:SELECT COUNT(DISTINCT (p.ID)) FROM Person p INNER JOIN PersonRole pr ON p.ID=pr.person_ID WHERE p.userId=:userId AND pr.roleName='PSI Global Admin'"), + @NamedQuery(name="createQuery", query="sql:SELECT COUNT(DISTINCT (p.ID)) FROM Person p INNER JOIN PersonRole pr ON p.ID=pr.person_ID WHERE p.userId=:userId AND pr.roleName='PSI Global Admin'"), + @NamedQuery(name="deleteQuery", query="sql:SELECT COUNT(DISTINCT (p.ID)) FROM Person p INNER JOIN PersonRole pr ON p.ID=pr.person_ID WHERE p.userId=:userId AND pr.roleName='PSI Global Admin' AND (SELECT COUNT(ae.ID) FROM AccountingEntity ae WHERE ae.country_ID=:id) = 0 AND (SELECT COUNT(pa.ID) FROM PostalAddress pa WHERE pa.country_ID=:id) = 0 AND (SELECT COUNT(vp.ID) FROM VarietyPatent vp WHERE vp.country_ID=:id) = 0") +}) +/* +*/ +public class _Super_Country extends BaseDataObject implements Serializable +{ + ////////////////////////////////////////////////////// + // VERSION + ////////////////////////////////////////////////////// + @Override + public String classVersion() { + return "0.0.0"; + } + + + ////////////////////////////////////////////////////// + // ID + ////////////////////////////////////////////////////// + @Id + @com.percero.agents.sync.metadata.annotations.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 + @com.percero.agents.sync.metadata.annotations.Externalize + private String abbreviation; + public String getAbbreviation() { + return this.abbreviation; + } + public void setAbbreviation(String value) + { + this.abbreviation = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private Boolean requiresPermit; + public Boolean getRequiresPermit() { + return this.requiresPermit; + } + public void setRequiresPermit(Boolean value) + { + this.requiresPermit = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private String name; + public String getName() { + return this.name; + } + public void setName(String value) + { + this.name = value; + } + + + ////////////////////////////////////////////////////// + // Source Relationships + ////////////////////////////////////////////////////// + + + ////////////////////////////////////////////////////// + // Target Relationships + ////////////////////////////////////////////////////// + + + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + StringBuilder objectJson = new StringBuilder(super.retrieveJson(objectMapper)); + + // Properties + objectJson.append(",\"abbreviation\":"); + if (getAbbreviation() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getAbbreviation())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + objectJson.append(",\"requiresPermit\":"); + if (getRequiresPermit() == null) + objectJson.append("null"); + else { + objectJson.append(getRequiresPermit()); + } + + objectJson.append(",\"name\":"); + if (getName() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getName())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + // Source Relationships + + // Target Relationships + + + return objectJson.toString(); + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + setAbbreviation(JsonUtils.getJsonString(jsonObject, "abbreviation")); + setRequiresPermit(JsonUtils.getJsonBoolean(jsonObject, "requiresPermit")); + setName(JsonUtils.getJsonString(jsonObject, "name")); + + // Source Relationships + + // Target Relationships + } + + @Override + protected List getListSetters() { + List listSetters = super.getListSetters(); + + // Target Relationships + listSetters.add(MappedClass.getFieldSetters(CountryPermit.class, "country")); + listSetters.add(MappedClass.getFieldSetters(PostalAddress.class, "country")); + + return listSetters; + } +} \ No newline at end of file diff --git a/src/test/java/com/percero/example/mo_super/_Super_CountryPermit.java b/src/test/java/com/percero/example/mo_super/_Super_CountryPermit.java new file mode 100644 index 0000000..4f4e0c1 --- /dev/null +++ b/src/test/java/com/percero/example/mo_super/_Super_CountryPermit.java @@ -0,0 +1,257 @@ +package com.percero.example.mo_super; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MappedSuperclass; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; + +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.annotate.JsonDeserialize; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +import com.google.gson.JsonObject; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClass.MappedClassMethodPair; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.example.Country; +import com.percero.example.PermitDocument; +import com.percero.example.PermitLine; +import com.percero.example.PostalAddress; +import com.percero.serial.BDODeserializer; +import com.percero.serial.BDOSerializer; +import com.percero.serial.JsonUtils; + +@MappedSuperclass +/* +*/ +public class _Super_CountryPermit extends BaseDataObject implements Serializable +{ + ////////////////////////////////////////////////////// + // VERSION + ////////////////////////////////////////////////////// + @Override + public String classVersion() { + return "0.0.0"; + } + + + ////////////////////////////////////////////////////// + // ID + ////////////////////////////////////////////////////// + @Id + @com.percero.agents.sync.metadata.annotations.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 + @com.percero.agents.sync.metadata.annotations.Externalize + private Double quantity; + public Double getQuantity() { + return this.quantity; + } + public void setQuantity(Double value) + { + this.quantity = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private Date expirationDate; + public Date getExpirationDate() { + return this.expirationDate; + } + public void setExpirationDate(Date value) + { + this.expirationDate = value; + } + + + ////////////////////////////////////////////////////// + // Source Relationships + ////////////////////////////////////////////////////// + @com.percero.agents.sync.metadata.annotations.Externalize + @JsonSerialize(using=BDOSerializer.class) + @JsonDeserialize(using=BDODeserializer.class) + @JoinColumn(name="country_ID") + @org.hibernate.annotations.ForeignKey(name="FK_Country_country_TO_CountryPermit") + @ManyToOne(fetch=FetchType.LAZY, optional=false) + private Country country; + public Country getCountry() { + return this.country; + } + public void setCountry(Country value) { + this.country = value; + } + + @com.percero.agents.sync.metadata.annotations.Externalize + @JsonSerialize(using=BDOSerializer.class) + @JsonDeserialize(using=BDODeserializer.class) + @JoinColumn(name="issuerAddress_ID") + @org.hibernate.annotations.ForeignKey(name="FK_PostalAddress_issuerAddress_TO_CountryPermit") + @OneToOne(fetch=FetchType.LAZY) + private PostalAddress issuerAddress; + public PostalAddress getIssuerAddress() { + return this.issuerAddress; + } + public void setIssuerAddress(PostalAddress value) { + this.issuerAddress = value; + } + + + ////////////////////////////////////////////////////// + // Target Relationships + ////////////////////////////////////////////////////// + @com.percero.agents.sync.metadata.annotations.Externalize + @JsonSerialize(contentUsing=BDOSerializer.class) + @JsonDeserialize(contentUsing=BDODeserializer.class) + @OneToMany(fetch=FetchType.LAZY, targetEntity=PermitLine.class, mappedBy="countryPermit", cascade=javax.persistence.CascadeType.REMOVE) + private List permitLines; + public List getPermitLines() { + return this.permitLines; + } + public void setPermitLines(List value) { + this.permitLines = value; + } + + @JsonSerialize(using=BDOSerializer.class) + @JsonDeserialize(using=BDODeserializer.class) + @com.percero.agents.sync.metadata.annotations.Externalize + @JoinColumn(name="permitDocument_ID") + @org.hibernate.annotations.ForeignKey(name="FK_CountryPermit_permitDoc_PermitDocument") + @OneToOne(fetch=FetchType.LAZY, mappedBy="countryPermit", cascade=javax.persistence.CascadeType.REMOVE) + private PermitDocument permitDocument; + public PermitDocument getPermitDocument() { + return this.permitDocument; + } + public void setPermitDocument(PermitDocument value) { + this.permitDocument = value; + } + + + + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + StringBuilder objectJson = new StringBuilder(super.retrieveJson(objectMapper)); + + // Properties + objectJson.append(",\"quantity\":"); + if (getQuantity() == null) + objectJson.append("null"); + else { + objectJson.append(getQuantity()); + } + + objectJson.append(",\"expirationDate\":"); + if (getExpirationDate() == null) + objectJson.append("null"); + else { + objectJson.append(getExpirationDate().getTime()); + } + + // Source Relationships + objectJson.append(",\"country\":"); + if (getCountry() == null) + objectJson.append("null"); + else { + try { + objectJson.append(((BaseDataObject) getCountry()).toEmbeddedJson()); + } catch(Exception e) { + objectJson.append("null"); + } + } + + objectJson.append(",\"issuerAddress\":"); + if (getIssuerAddress() == null) + objectJson.append("null"); + else { + try { + objectJson.append(((BaseDataObject) getIssuerAddress()).toEmbeddedJson()); + } catch(Exception e) { + objectJson.append("null"); + } + } + + // Target Relationships + objectJson.append(",\"permitLines\":["); + if (getPermitLines() != null) { + int permitLinesCounter = 0; + for(PermitLine nextPermitLines : getPermitLines()) { + if (permitLinesCounter > 0) + objectJson.append(','); + try { + objectJson.append(((BaseDataObject) nextPermitLines).toEmbeddedJson()); + permitLinesCounter++; + } catch(Exception e) { + // Do nothing. + } + } + } + objectJson.append(']'); + + objectJson.append(",\"permitDocument\":"); + if (getPermitDocument() == null) + objectJson.append("null"); + else { + try { + objectJson.append(((BaseDataObject) getPermitDocument()).toEmbeddedJson()); + } catch(Exception e) { + objectJson.append("null"); + } + } + + + return objectJson.toString(); + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + setQuantity(JsonUtils.getJsonDouble(jsonObject, "quantity")); + setExpirationDate(JsonUtils.getJsonDate(jsonObject, "expirationDate")); + + // Source Relationships + this.country = JsonUtils.getJsonPerceroObject(jsonObject, "country"); + this.issuerAddress = JsonUtils.getJsonPerceroObject(jsonObject, "issuerAddress"); + + // Target Relationships + this.permitLines = (List) JsonUtils.getJsonListPerceroObject(jsonObject, "permitLines"); + this.permitDocument = JsonUtils.getJsonPerceroObject(jsonObject, "permitDocument"); + } + + @Override + protected List getListSetters() { + List listSetters = super.getListSetters(); + + // Target Relationships + listSetters.add(MappedClass.getFieldSetters(PermitLine.class, "countryPermit")); + listSetters.add(MappedClass.getFieldSetters(PermitDocument.class, "countryPermit")); + + return listSetters; + } +} \ No newline at end of file diff --git a/src/test/java/com/percero/example/mo_super/_Super_PermitDocument.java b/src/test/java/com/percero/example/mo_super/_Super_PermitDocument.java new file mode 100644 index 0000000..c302597 --- /dev/null +++ b/src/test/java/com/percero/example/mo_super/_Super_PermitDocument.java @@ -0,0 +1,164 @@ +package com.percero.example.mo_super; + +import java.io.IOException; +import java.io.Serializable; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.MappedSuperclass; +import javax.persistence.OneToOne; + +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 com.google.gson.JsonObject; +import com.percero.agents.sync.metadata.MappedClass.MappedClassMethodPair; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.example.CountryPermit; +import com.percero.serial.BDODeserializer; +import com.percero.serial.BDOSerializer; +import com.percero.serial.JsonUtils; + +@MappedSuperclass +/* +*/ +public class _Super_PermitDocument extends BaseDataObject implements Serializable +{ + ////////////////////////////////////////////////////// + // VERSION + ////////////////////////////////////////////////////// + @Override + public String classVersion() { + return "0.0.0.0"; + } + + + ////////////////////////////////////////////////////// + // ID + ////////////////////////////////////////////////////// + @Id + @com.percero.agents.sync.metadata.annotations.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 + @com.percero.agents.sync.metadata.annotations.Externalize + private byte[] documentContent; + public byte[] getDocumentContent() { + return this.documentContent; + } + public void setDocumentContent(byte[] value) + { + this.documentContent = value; + } + + + ////////////////////////////////////////////////////// + // Source Relationships + ////////////////////////////////////////////////////// + @com.percero.agents.sync.metadata.annotations.Externalize + @JsonSerialize(using=BDOSerializer.class) + @JsonDeserialize(using=BDODeserializer.class) + @JoinColumn(name="countryPermit_ID") + @org.hibernate.annotations.ForeignKey(name="FK_CountryPermit_countryPermit_TO_PermitDocument") + @OneToOne(fetch=FetchType.LAZY, optional=false) + private CountryPermit countryPermit; + public CountryPermit getCountryPermit() { + return this.countryPermit; + } + public void setCountryPermit(CountryPermit value) { + this.countryPermit = value; + } + + + ////////////////////////////////////////////////////// + // Target Relationships + ////////////////////////////////////////////////////// + + + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + StringBuilder objectJson = new StringBuilder(super.retrieveJson(objectMapper)); + + // Properties + objectJson.append(",\"documentContent\":"); + if (getDocumentContent() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getDocumentContent())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + // Source Relationships + objectJson.append(",\"countryPermit\":"); + if (getCountryPermit() == null) + objectJson.append("null"); + else { + try { + objectJson.append(((BaseDataObject) getCountryPermit()).toEmbeddedJson()); + } catch(Exception e) { + objectJson.append("null"); + } + } + + // Target Relationships + + return objectJson.toString(); + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + setDocumentContent(JsonUtils.getJsonByteArray(jsonObject, "documentContent")); + + // Source Relationships + this.countryPermit = JsonUtils.getJsonPerceroObject(jsonObject, "countryPermit"); + + // Target Relationships + } + + @Override + protected List getListSetters() { + List listSetters = super.getListSetters(); + + // Target Relationships + + return listSetters; + } +} \ No newline at end of file diff --git a/src/test/java/com/percero/example/mo_super/_Super_PermitLine.java b/src/test/java/com/percero/example/mo_super/_Super_PermitLine.java new file mode 100644 index 0000000..e9bc05c --- /dev/null +++ b/src/test/java/com/percero/example/mo_super/_Super_PermitLine.java @@ -0,0 +1,148 @@ +package com.percero.example.mo_super; + +import java.io.Serializable; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MappedSuperclass; + +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.annotate.JsonDeserialize; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +import com.google.gson.JsonObject; +import com.percero.agents.sync.metadata.MappedClass.MappedClassMethodPair; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.example.CountryPermit; +import com.percero.serial.BDODeserializer; +import com.percero.serial.BDOSerializer; +import com.percero.serial.JsonUtils; + +@MappedSuperclass +/* +*/ +public class _Super_PermitLine extends BaseDataObject implements Serializable +{ + ////////////////////////////////////////////////////// + // VERSION + ////////////////////////////////////////////////////// + @Override + public String classVersion() { + return "0.0.0"; + } + + + ////////////////////////////////////////////////////// + // ID + ////////////////////////////////////////////////////// + @Id + @com.percero.agents.sync.metadata.annotations.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 + @com.percero.agents.sync.metadata.annotations.Externalize + private Double quantity; + public Double getQuantity() { + return this.quantity; + } + public void setQuantity(Double value) + { + this.quantity = value; + } + + + ////////////////////////////////////////////////////// + // Source Relationships + ////////////////////////////////////////////////////// + @com.percero.agents.sync.metadata.annotations.Externalize + @JsonSerialize(using=BDOSerializer.class) + @JsonDeserialize(using=BDODeserializer.class) + @JoinColumn(name="countryPermit_ID") + @org.hibernate.annotations.ForeignKey(name="FK_CountryPermit_countryPermit_TO_PermitLine") + @ManyToOne(fetch=FetchType.LAZY, optional=false) + private CountryPermit countryPermit; + public CountryPermit getCountryPermit() { + return this.countryPermit; + } + public void setCountryPermit(CountryPermit value) { + this.countryPermit = value; + } + + + ////////////////////////////////////////////////////// + // Target Relationships + ////////////////////////////////////////////////////// + + + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + StringBuilder objectJson = new StringBuilder(super.retrieveJson(objectMapper)); + + // Properties + objectJson.append(",\"quantity\":"); + if (getQuantity() == null) + objectJson.append("null"); + else { + objectJson.append(getQuantity()); + } + + // Source Relationships + objectJson.append(",\"countryPermit\":"); + if (getCountryPermit() == null) + objectJson.append("null"); + else { + try { + objectJson.append(((BaseDataObject) getCountryPermit()).toEmbeddedJson()); + } catch(Exception e) { + objectJson.append("null"); + } + } + + // Target Relationships + + return objectJson.toString(); + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + setQuantity(JsonUtils.getJsonDouble(jsonObject, "quantity")); + + // Source Relationships + this.countryPermit = JsonUtils.getJsonPerceroObject(jsonObject, "countryPermit"); + + // Target Relationships + } + + @Override + protected List getListSetters() { + List listSetters = super.getListSetters(); + + // Target Relationships + + return listSetters; + } +} \ No newline at end of file diff --git a/src/test/java/com/percero/example/mo_super/_Super_PostalAddress.java b/src/test/java/com/percero/example/mo_super/_Super_PostalAddress.java new file mode 100644 index 0000000..5e6782f --- /dev/null +++ b/src/test/java/com/percero/example/mo_super/_Super_PostalAddress.java @@ -0,0 +1,495 @@ +package com.percero.example.mo_super; + +import java.io.IOException; +import java.io.Serializable; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MappedSuperclass; +import javax.persistence.OneToOne; + +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 com.google.gson.JsonObject; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClass.MappedClassMethodPair; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.example.Country; +import com.percero.example.CountryPermit; +import com.percero.serial.BDODeserializer; +import com.percero.serial.BDOSerializer; +import com.percero.serial.JsonUtils; + +@MappedSuperclass +//@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) +@Inheritance(strategy=InheritanceType.JOINED) +/* +*/ +public class _Super_PostalAddress extends BaseDataObject implements Serializable +{ + ////////////////////////////////////////////////////// + // VERSION + ////////////////////////////////////////////////////// + @Override + public String classVersion() { + return "0.0.0"; + } + + + ////////////////////////////////////////////////////// + // ID + ////////////////////////////////////////////////////// + @Id + @com.percero.agents.sync.metadata.annotations.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 + @com.percero.agents.sync.metadata.annotations.Externalize + private String address1; + public String getAddress1() { + return this.address1; + } + public void setAddress1(String value) + { + this.address1 = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private String address2; + public String getAddress2() { + return this.address2; + } + public void setAddress2(String value) + { + this.address2 = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private String address3; + public String getAddress3() { + return this.address3; + } + public void setAddress3(String value) + { + this.address3 = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private String city; + public String getCity() { + return this.city; + } + public void setCity(String value) + { + this.city = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private String state; + public String getState() { + return this.state; + } + public void setState(String value) + { + this.state = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private String postalCode; + public String getPostalCode() { + return this.postalCode; + } + public void setPostalCode(String value) + { + this.postalCode = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private String name; + public String getName() { + return this.name; + } + public void setName(String value) + { + this.name = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private Double latitude; + public Double getLatitude() { + return this.latitude; + } + public void setLatitude(Double value) + { + this.latitude = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private Double longitude; + public Double getLongitude() { + return this.longitude; + } + public void setLongitude(Double value) + { + this.longitude = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private String abbreviation; + public String getAbbreviation() { + return this.abbreviation; + } + public void setAbbreviation(String value) + { + this.abbreviation = value; + } + + @Column + @com.percero.agents.sync.metadata.annotations.Externalize + private String countyName; + public String getCountyName() { + return this.countyName; + } + public void setCountyName(String value) + { + this.countyName = value; + } + + + ////////////////////////////////////////////////////// + // Source Relationships + ////////////////////////////////////////////////////// + @com.percero.agents.sync.metadata.annotations.Externalize + @JsonSerialize(using=BDOSerializer.class) + @JsonDeserialize(using=BDODeserializer.class) + @JoinColumn(name="country_ID") + @org.hibernate.annotations.ForeignKey(name="FK_Country_country_TO_PostalAddress") + @ManyToOne(fetch=FetchType.LAZY) + private Country country; + public Country getCountry() { + return this.country; + } + public void setCountry(Country value) { + this.country = value; + } + + + ////////////////////////////////////////////////////// + // Target Relationships + ////////////////////////////////////////////////////// + /** + * The address of the entiy that issued the import permit. Used to determing the "Issuing County" for Packing Lists. + */ + @JsonSerialize(using=BDOSerializer.class) + @JsonDeserialize(using=BDODeserializer.class) + @com.percero.agents.sync.metadata.annotations.Externalize + @JoinColumn(name="countryPermit_ID") + @org.hibernate.annotations.ForeignKey(name="FK_PostalAddress_countryPermit_CountryPermit") + @OneToOne(fetch=FetchType.LAZY, mappedBy="issuerAddress", cascade=javax.persistence.CascadeType.REMOVE) + private CountryPermit countryPermit; + public CountryPermit getCountryPermit() { + return this.countryPermit; + } + public void setCountryPermit(CountryPermit value) { + this.countryPermit = value; + } + + + + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + StringBuilder objectJson = new StringBuilder(super.retrieveJson(objectMapper)); + + // Properties + objectJson.append(",\"address1\":"); + if (getAddress1() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getAddress1())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + objectJson.append(",\"address2\":"); + if (getAddress2() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getAddress2())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + objectJson.append(",\"address3\":"); + if (getAddress3() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getAddress3())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + objectJson.append(",\"city\":"); + if (getCity() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getCity())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + objectJson.append(",\"state\":"); + if (getState() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getState())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + objectJson.append(",\"postalCode\":"); + if (getPostalCode() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getPostalCode())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + objectJson.append(",\"name\":"); + if (getName() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getName())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + objectJson.append(",\"latitude\":"); + if (getLatitude() == null) + objectJson.append("null"); + else { + objectJson.append(getLatitude()); + } + + objectJson.append(",\"longitude\":"); + if (getLongitude() == null) + objectJson.append("null"); + else { + objectJson.append(getLongitude()); + } + + objectJson.append(",\"abbreviation\":"); + if (getAbbreviation() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getAbbreviation())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + objectJson.append(",\"countyName\":"); + if (getCountyName() == null) + objectJson.append("null"); + else { + if (objectMapper == null) + objectMapper = new ObjectMapper(); + try { + objectJson.append(objectMapper.writeValueAsString(getCountyName())); + } catch (JsonGenerationException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (JsonMappingException e) { + objectJson.append("null"); + e.printStackTrace(); + } catch (IOException e) { + objectJson.append("null"); + e.printStackTrace(); + } + } + + // Source Relationships + objectJson.append(",\"country\":"); + if (getCountry() == null) + objectJson.append("null"); + else { + try { + objectJson.append(((BaseDataObject) getCountry()).toEmbeddedJson()); + } catch(Exception e) { + objectJson.append("null"); + } + } + + // Target Relationships + objectJson.append(",\"countryPermit\":"); + if (getCountryPermit() == null) + objectJson.append("null"); + else { + try { + objectJson.append(((BaseDataObject) getCountryPermit()).toEmbeddedJson()); + } catch(Exception e) { + objectJson.append("null"); + } + } + + + return objectJson.toString(); + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + setAddress1(JsonUtils.getJsonString(jsonObject, "address1")); + setAddress2(JsonUtils.getJsonString(jsonObject, "address2")); + setAddress3(JsonUtils.getJsonString(jsonObject, "address3")); + setCity(JsonUtils.getJsonString(jsonObject, "city")); + setState(JsonUtils.getJsonString(jsonObject, "state")); + setPostalCode(JsonUtils.getJsonString(jsonObject, "postalCode")); + setName(JsonUtils.getJsonString(jsonObject, "name")); + setLatitude(JsonUtils.getJsonDouble(jsonObject, "latitude")); + setLongitude(JsonUtils.getJsonDouble(jsonObject, "longitude")); + setAbbreviation(JsonUtils.getJsonString(jsonObject, "abbreviation")); + setCountyName(JsonUtils.getJsonString(jsonObject, "countyName")); + + // Source Relationships + this.country = JsonUtils.getJsonPerceroObject(jsonObject, "country"); + + // Target Relationships + this.countryPermit = JsonUtils.getJsonPerceroObject(jsonObject, "countryPermit"); + } + + @Override + protected List getListSetters() { + List listSetters = super.getListSetters(); + + // Target Relationships + listSetters.add(MappedClass.getFieldSetters(CountryPermit.class, "issuerAddress")); + + return listSetters; + } +} \ No newline at end of file diff --git a/src/test/java/com/percero/example/mo_super/_Super_ShippingAddress.java b/src/test/java/com/percero/example/mo_super/_Super_ShippingAddress.java new file mode 100644 index 0000000..33362d6 --- /dev/null +++ b/src/test/java/com/percero/example/mo_super/_Super_ShippingAddress.java @@ -0,0 +1,78 @@ +package com.percero.example.mo_super; + +import java.util.List; + +import javax.persistence.MappedSuperclass; +import javax.persistence.SecondaryTable; + +import org.codehaus.jackson.map.ObjectMapper; + +import com.google.gson.JsonObject; +import com.percero.agents.sync.metadata.MappedClass.MappedClassMethodPair; + +@MappedSuperclass +@SecondaryTable(name="ShippingAddress") +/* +*/ +public class _Super_ShippingAddress extends com.percero.example.PostalAddress +{ + ////////////////////////////////////////////////////// + // VERSION + ////////////////////////////////////////////////////// + @Override + public String classVersion() { + return "0.0.0"; + } + + + ////////////////////////////////////////////////////// + // ID + ////////////////////////////////////////////////////// + /** Inherits from another Model Object Class, so no ID here. **/ + + ////////////////////////////////////////////////////// + // Properties + ////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////// + // Source Relationships + ////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////// + // Target Relationships + ////////////////////////////////////////////////////// + + + + ////////////////////////////////////////////////////// + // JSON + ////////////////////////////////////////////////////// + @Override + public String retrieveJson(ObjectMapper objectMapper) { + StringBuilder objectJson = new StringBuilder(super.retrieveJson(objectMapper)); + + // Properties + // Source Relationships + // Target Relationships + + return objectJson.toString(); + } + + @Override + protected void fromJson(JsonObject jsonObject) { + super.fromJson(jsonObject); + + // Properties + + // Source Relationships + + // Target Relationships + } + + @Override + protected List getListSetters() { + List listSetters = super.getListSetters(); + + return listSetters; + } +} \ No newline at end of file diff --git a/src/test/java/com/percero/util/TestMappedClassUtils.java b/src/test/java/com/percero/util/TestMappedClassUtils.java new file mode 100644 index 0000000..3438674 --- /dev/null +++ b/src/test/java/com/percero/util/TestMappedClassUtils.java @@ -0,0 +1,62 @@ +package com.percero.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.percero.example.PostalAddress; + +public class TestMappedClassUtils { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testGetClassFields() { + List result = MappedClassUtils.getClassFields(PostalAddress.class); + + assertNotNull(result); + assertEquals(17, result.size()); + } + + @Test + public void testGetFieldGetters() throws NoSuchFieldException, SecurityException { + List fields = MappedClassUtils.getClassFields(PostalAddress.class); + for(Field field : fields) { + Method result = MappedClassUtils.getFieldGetters(PostalAddress.class, field); + assertNotNull(result); + } + } + + @Test + public void testGetFieldSetters() throws NoSuchFieldException, SecurityException { + List fields = MappedClassUtils.getClassFields(PostalAddress.class); + for(Field field : fields) { + Method result = MappedClassUtils.getFieldSetters(PostalAddress.class, field); + assertNotNull(result); + } + } + +} diff --git a/src/test/resources/properties/test/env.properties b/src/test/resources/properties/test/env.properties index fcc8219..abd7b52 100644 --- a/src/test/resources/properties/test/env.properties +++ b/src/test/resources/properties/test/env.properties @@ -9,6 +9,7 @@ storeHistory=false # Application Database Details databaseProject.driverClassName=com.mysql.jdbc.Driver +databaseProject.jdbcUrl=jdbc:mysql://localhost:3306/as_Example?autoReconnect=true databaseProject.host=localhost databaseProject.port=3306 databaseProject.dbname=as_example @@ -17,6 +18,7 @@ databaseProject.password=root # AuthAgent Database Details databaseAuth.driverClassName=com.mysql.jdbc.Driver +databaseAuth.jdbcUrl=jdbc:mysql://localhost:3306/as_Example?autoReconnect=true databaseAuth.host=localhost databaseAuth.port=3306 databaseAuth.dbname=as_example diff --git a/src/test/resources/spring/basic_components_spring_config.xml b/src/test/resources/spring/basic_components_spring_config.xml new file mode 100644 index 0000000..23cd080 --- /dev/null +++ b/src/test/resources/spring/basic_components_spring_config.xml @@ -0,0 +1,348 @@ + + + + + + + + + + + + classpath:properties/test/env.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + hibernate.dialect=org.hibernate.dialect.MySQLDialect + + hibernate.hbm2ddl.auto=$pf{databaseAuth.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 + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/spring/percero-spring-config.xml b/src/test/resources/spring/percero-spring-config.xml new file mode 100644 index 0000000..38c7038 --- /dev/null +++ b/src/test/resources/spring/percero-spring-config.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/spring/update_table_processor.xml b/src/test/resources/spring/update_table_processor.xml index 9d0ba64..4c1570b 100644 --- a/src/test/resources/spring/update_table_processor.xml +++ b/src/test/resources/spring/update_table_processor.xml @@ -34,6 +34,7 @@ + @@ -154,7 +155,7 @@ - + @@ -174,7 +175,7 @@ destroy-method="close" id="dataSource1"> + value="$pf{databaseAuth.jdbcUrl}" /> @@ -276,7 +277,7 @@ destroy-method="close" id="dataSourceProject"> + value="$pf{databaseProject.jdbcUrl}" /> diff --git a/src/test/resources/updateTableMap.yml b/src/test/resources/updateTableMap.yml new file mode 100644 index 0000000..c56ef1a --- /dev/null +++ b/src/test/resources/updateTableMap.yml @@ -0,0 +1,8 @@ +tableName: Email +classNames: + - com.percero.example.Email +--- +tableName: Person +classNames: + - com.percero.example.Person +---