diff --git a/.gitignore b/.gitignore index 54b685e..fb4f905 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ target/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + +/.classpath +/.project +/.settings/ diff --git a/pom.xml b/pom.xml index d324003..81381a4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.activestack + org.activestack syncengine 1.1.15-SNAPSHOT @@ -14,6 +14,7 @@ 1.6.1 1.19.0 1.19.0 + 1.9.5 @@ -33,6 +34,12 @@ 4.8.2 test + + org.mockito + mockito-core + ${mockito-core.version} + test + org.codehaus.jackson diff --git a/src/main/java/com/percero/agents/auth/helpers/AccountHelper.java b/src/main/java/com/percero/agents/auth/helpers/AccountHelper.java index dca0075..bf1cfb7 100644 --- a/src/main/java/com/percero/agents/auth/helpers/AccountHelper.java +++ b/src/main/java/com/percero/agents/auth/helpers/AccountHelper.java @@ -701,7 +701,7 @@ public void setupUserRoles(String userId, List serviceUserList) thr Boolean isInaccurateList = false; for (ServiceUser nextServiceUser : serviceUserList) { if (!nextServiceUser.getAreRoleNamesAccurate()) { - log.debug("Ignoring role names from " + nextServiceUser.getAuthProvider().toString()); + log.debug("Ignoring role names from " + nextServiceUser.getAuthProviderID().toString()); isInaccurateList = true; break; } diff --git a/src/main/java/com/percero/agents/auth/services/AnonAuthProvider.java b/src/main/java/com/percero/agents/auth/services/AnonAuthProvider.java new file mode 100644 index 0000000..629131c --- /dev/null +++ b/src/main/java/com/percero/agents/auth/services/AnonAuthProvider.java @@ -0,0 +1,56 @@ +package com.percero.agents.auth.services; + +import com.percero.agents.auth.vo.AuthProvider; +import com.percero.agents.auth.vo.ServiceIdentifier; +import com.percero.agents.auth.vo.ServiceOrganization; +import com.percero.agents.auth.vo.ServiceUser; +import com.percero.util.RandomStringGenerator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by jonnysamps on 8/14/15. + */ +@Component +public class AnonAuthProvider implements IAuthProvider { + private static String ID = "anonymous"; + + @Autowired + @Value("$pf{anonAuth.enabled:false}") + Boolean anonAuthEnabled = false; + @Autowired @Value("$pf{anonAuth.code:ANON}") + String anonAuthCode = "ANON"; + @Autowired @Value("$pf{anonAuth.roleNames:}") + String anonAuthRoleNames = ""; + + public String getID() { + return ID; + } + + public ServiceUser authenticate(String credential) { + ServiceUser serviceUser = new ServiceUser(); + serviceUser.setFirstName("ANON"); + serviceUser.setLastName("ANON"); + serviceUser.setId("ANON"); + serviceUser.setAuthProviderID(AuthProvider.ANON.toString()); + + 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); + + String email = "anonymous@activestack.io"; + serviceUser.getEmails().add(email); + serviceUser.getIdentifiers().add(new ServiceIdentifier("email", email)); + + return serviceUser; + } +} diff --git a/src/main/java/com/percero/agents/auth/services/AuthProviderRegistry.java b/src/main/java/com/percero/agents/auth/services/AuthProviderRegistry.java new file mode 100644 index 0000000..b2e43a1 --- /dev/null +++ b/src/main/java/com/percero/agents/auth/services/AuthProviderRegistry.java @@ -0,0 +1,58 @@ +package com.percero.agents.auth.services; + +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Class is the registration point for IAuthProviders. + */ +@Component +public class AuthProviderRegistry { + private static Logger logger = Logger.getLogger(AuthProviderRegistry.class); + private Map providerMap = new HashMap(); + + /** + * Intended to be a default registration point for all IAuthProviders in the application context + * @param providers + */ + @Autowired(required = false) + public void setProviders(Collection providers){ + for(IAuthProvider provider : providers){ + this.addProvider(provider); + } + } + + /** + * Add a provider to the registry + * @param provider + */ + public void addProvider(IAuthProvider provider){ + if(providerMap.containsKey(provider.getID())) + logger.warn("Non-unique auth provider ID: "+provider.getID()); + + providerMap.put(provider.getID(), provider); + } + + /** + * Find a provider by ID + * @param ID + * @return + */ + public IAuthProvider getProvider(String ID){ + return providerMap.get(ID); + } + + /** + * Returns true if registry has a provider registered for this key + * @param ID + * @return + */ + public boolean hasProvider(String ID){ + return providerMap.containsKey(ID); + } +} 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 d7079be..bc833d0 100644 --- a/src/main/java/com/percero/agents/auth/services/AuthService.java +++ b/src/main/java/com/percero/agents/auth/services/AuthService.java @@ -41,8 +41,6 @@ import com.percero.agents.auth.vo.UserToken; import com.percero.agents.sync.access.IAccessManager; -import edu.emory.mathcs.backport.java.util.Arrays; - /** * The AuthService is responsible for managing authentication of users within the Percero framework. The AuthService * maintains its own separate database that generically references users. Implementations of IAuthHelper's provide @@ -129,20 +127,20 @@ protected List findByExample(Object theQueryObject, /* (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) */ - public OAuthResponse authenticateOAuthCode(AuthProvider authProvider, String code, String clientId, String deviceId, String redirectUrl, OAuthToken requestToken){ + public OAuthResponse authenticateOAuthCode(String authProviderID, String code, String clientId, String deviceId, String redirectUrl, OAuthToken requestToken){ - Object accessTokenResult = getServiceProviderAccessToken(authProvider, code, redirectUrl, requestToken); + Object accessTokenResult = getServiceProviderAccessToken(authProviderID, code, redirectUrl, requestToken); if (accessTokenResult == null) return null; if (accessTokenResult instanceof ServiceUser) { ServiceUser serviceUser = (ServiceUser) accessTokenResult; - serviceUser.setAuthProvider(authProvider); - return setupServiceUser(authProvider, serviceUser, clientId, deviceId); + serviceUser.setAuthProviderID(authProviderID.toString()); + return setupServiceUser(authProviderID, serviceUser, clientId, deviceId); } else if (accessTokenResult instanceof OAuthToken){ OAuthToken token = (OAuthToken) accessTokenResult; - return authenticateOAuthAccessToken(authProvider, token.getToken(), token.getTokenSecret(), clientId, deviceId, false); + return authenticateOAuthAccessToken(authProviderID, token.getToken(), token.getTokenSecret(), clientId, deviceId, false); } else { log.error("Invalid access token result in authenticateOAuthCode"); @@ -150,11 +148,11 @@ else if (accessTokenResult instanceof OAuthToken){ } } - protected Object getServiceProviderAccessToken(AuthProvider authProvider, String code, String redirectUrl, OAuthToken requestToken) { + protected Object getServiceProviderAccessToken(String authProviderID, String code, String redirectUrl, OAuthToken requestToken) { OAuthToken token = null; try { - /*if (authProvider.equals(AuthProvider.LINKEDIN)) { + /*if (authProviderID.equals(AuthProvider.LINKEDIN)) { // LinkedInHelper linkedInHelper = new LinkedInHelper(); // token = linkedInHelper.getAccessToken(svcOAuth.getAppKey(), svcOAuthSecret.getAppToken(), code, requestToken); } @@ -162,24 +160,25 @@ protected Object getServiceProviderAccessToken(AuthProvider authProvider, String // //oauthToken = FacebookHelper.getRequestToken(svcOauth.getAppKey(), svcOauthSecret.getAppToken()); // throw new IllegalArgumentException("Facebook OAuth Not supported"); // } - else */if (authProvider.equals(AuthProvider.GOOGLE)) { + else */ + if (authProviderID.equals(AuthProvider.GOOGLE.toString())) { ServiceUser serviceUser = googleHelper.authenticateOAuthCode(code, redirectUrl); return serviceUser; } - else if (authProvider.equals(AuthProvider.LINKEDIN)) { + else if (authProviderID.equals(AuthProvider.LINKEDIN.toString())) { ServiceUser serviceUser = linkedInHelper.authenticateOAuthCode(code, redirectUrl); return serviceUser; } - else if (authProvider.equals(AuthProvider.FACEBOOK)) { + else if (authProviderID.equals(AuthProvider.FACEBOOK.toString())) { ServiceUser serviceUser = facebookHelper.authenticateOAuthCode(code, redirectUrl); return serviceUser; } - else if (authProvider.equals(AuthProvider.GITHUB)) { + else if (authProviderID.equals(AuthProvider.GITHUB.toString())) { String accessToken = githubHelper.getAccessTokenResponse(code, redirectUrl); token = new OAuthToken(); token.setToken(accessToken); } - else if(authProvider.equals(AuthProvider.ANON)){ + else if(authProviderID.equals(AuthProvider.ANON.toString())){ token = new OAuthToken(); token.setToken("ANON"); token.setTokenSecret("ANON"); @@ -194,31 +193,31 @@ else if(authProvider.equals(AuthProvider.ANON)){ /* (non-Javadoc) * @see com.com.percero.agents.auth.services.IAuthService#authenticateBasicOAuth(com.com.percero.agents.auth.vo.AuthProvider, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.com.percero.agents.auth.vo.OAuthToken) */ - public OAuthResponse authenticateBasicOAuth(AuthProvider authProvider, String userName, String password, String scopes, String appUrl, String clientId, String deviceId, OAuthToken requestToken){ + public OAuthResponse authenticateBasicOAuth(String authProviderID, String userName, String password, String scopes, String appUrl, String clientId, String deviceId, OAuthToken requestToken){ - OAuthToken token = getServiceProviderAccessTokenViaBasicAuth(authProvider, userName, password, scopes, appUrl, requestToken); + OAuthToken token = getServiceProviderAccessTokenViaBasicAuth(authProviderID, userName, password, scopes, appUrl, requestToken); if (token == null) return null; - return authenticateOAuthAccessToken(authProvider, token.getToken(), token.getTokenSecret(), clientId, deviceId, false); + return authenticateOAuthAccessToken(authProviderID, token.getToken(), token.getTokenSecret(), clientId, deviceId, false); } - protected OAuthToken getServiceProviderAccessTokenViaBasicAuth(AuthProvider authProvider, String userName, String password, String scopes, String appUrl, OAuthToken requestToken) { + protected OAuthToken getServiceProviderAccessTokenViaBasicAuth(String authProviderID, String userName, String password, String scopes, String appUrl, OAuthToken requestToken) { OAuthToken token = null; try { - if (authProvider.equals(AuthProvider.GITHUB)) { + if (authProviderID.equals(AuthProvider.GITHUB)) { String accessToken = githubHelper.getBasicAccessTokenResponse(userName, password, scopes, appUrl); token = new OAuthToken(); token.setToken(accessToken); } - else if(authProvider.equals(AuthProvider.ANON)){ + else if(authProviderID.equals(AuthProvider.ANON)){ token = new OAuthToken(); token.setToken("ANON"); token.setTokenSecret("ANON"); } else { - throw new IllegalArgumentException(authProvider.name() + " OAuth Not supported"); + throw new IllegalArgumentException(authProviderID + " OAuth Not supported"); } } catch (Exception e) { @@ -231,11 +230,11 @@ else if(authProvider.equals(AuthProvider.ANON)){ /* (non-Javadoc) * @see com.com.percero.agents.auth.services.IAuthService#authenticateOAuthAccessToken(com.com.percero.agents.auth.vo.AuthProvider, java.lang.String, java.lang.String, java.lang.String, java.lang.String) */ - public OAuthResponse authenticateOAuthAccessToken(AuthProvider authProvider, String accessToken, String refreshToken, String clientId, String deviceId) { - return authenticateOAuthAccessToken(authProvider, accessToken, refreshToken, clientId, deviceId, true); + public OAuthResponse authenticateOAuthAccessToken(String authProviderID, String accessToken, String refreshToken, String clientId, String deviceId) { + return authenticateOAuthAccessToken(authProviderID, accessToken, refreshToken, clientId, deviceId, true); } - public OAuthResponse authenticateOAuthAccessToken(AuthProvider authProvider, String accessToken, String refreshToken, String clientId, String deviceId, Boolean canOverideAccessToken) { + public OAuthResponse authenticateOAuthAccessToken(String authProviderID, String accessToken, String refreshToken, String clientId, String deviceId, Boolean canOverideAccessToken) { /** * The client may not actually have the refresh token. If not then we need to find it, because without a valid * refresh token then any "Auto-login" will fail after the token expires... which can cause client connections @@ -259,7 +258,7 @@ public OAuthResponse authenticateOAuthAccessToken(AuthProvider authProvider, Str if(user != null){ for(Object ob : user.getUserAccounts()){ UserAccount ua = (UserAccount)ob; - if(ua.getAuthProvider().equals(authProvider)){ + if(ua.getAuthProviderID().equals(authProviderID)){ refreshToken = ua.getRefreshToken(); accessToken = ua.getAccessToken(); break; @@ -269,14 +268,14 @@ public OAuthResponse authenticateOAuthAccessToken(AuthProvider authProvider, Str } - ServiceUser serviceUser = getServiceProviderServiceUser(accessToken, refreshToken, "", authProvider); + ServiceUser serviceUser = getServiceProviderServiceUser(accessToken, refreshToken, "", authProviderID); if (serviceUser == null) return null; else - return setupServiceUser(authProvider, serviceUser, clientId, deviceId); + return setupServiceUser(authProviderID, serviceUser, clientId, deviceId); } - public OAuthResponse setupServiceUser(AuthProvider authProvider, ServiceUser serviceUser, String clientId, String deviceId) { + public OAuthResponse setupServiceUser(String authProviderID, ServiceUser serviceUser, String clientId, String deviceId) { OAuthResponse result = null; UserToken userToken = null; @@ -301,7 +300,7 @@ public OAuthResponse setupServiceUser(AuthProvider authProvider, ServiceUser ser if(user != null){ for(Object ob : user.getUserAccounts()){ UserAccount ua = (UserAccount)ob; - if(ua.getAuthProvider().equals(authProvider)){ + if(ua.getAuthProviderID().equals(authProviderID)){ serviceUser.setRefreshToken(ua.getRefreshToken()); serviceUser.setAccessToken(ua.getAccessToken()); break; @@ -323,7 +322,7 @@ public OAuthResponse setupServiceUser(AuthProvider authProvider, ServiceUser ser queryUserAccount.setAccountId(accountId); queryUserAccount.setAccessToken(serviceUser.getAccessToken()); queryUserAccount.setRefreshToken(serviceUser.getRefreshToken()); - queryUserAccount.setAuthProvider(serviceUser.getAuthProvider()); + queryUserAccount.setAuthProviderID(serviceUser.getAuthProviderID()); UserAccount theFoundUserAccount = updateUserAccountToken(queryUserAccount, true, serviceUser); @@ -351,17 +350,17 @@ public OAuthResponse setupServiceUser(AuthProvider authProvider, ServiceUser ser // TODO: Need to check the Service Application only, NOT ALL Service Applications for this Service Provider. protected Boolean validateUserRoles(ServiceUser serviceUser, String userId) { - // Get list of role names required for this Auth provider - List authProviderRequiredSvcRoles = getSvcAppRoles(serviceUser.getAuthProvider()); + // Get list of role names required for this Auth authProviderID + List authProviderRequiredSvcRoles = getSvcAppRoles(serviceUser.getAuthProviderID()); - // If the auth provider requires no valid roles, then we have "foundMatchingRole" + // If the auth authProviderID requires no valid roles, then we have "foundMatchingRole" Boolean foundMatchingRole = (authProviderRequiredSvcRoles == null || authProviderRequiredSvcRoles.size() == 0); // Only check the ServiceUser roles list if role names for the ServiceUser are valid. if (serviceUser.getAreRoleNamesAccurate() && !foundMatchingRole) { Iterator itrSvcRoles = authProviderRequiredSvcRoles.iterator(); - // Check to see if the ServiceUser has at least one role that is in the required auth provider roles list. + // Check to see if the ServiceUser has at least one role that is in the required auth authProviderID roles list. while(!foundMatchingRole && itrSvcRoles.hasNext()) { SvcAppRole nextSvcAppRole = itrSvcRoles.next(); for(String nextRole : serviceUser.getRoleNames()) { @@ -373,7 +372,7 @@ protected Boolean validateUserRoles(ServiceUser serviceUser, String userId) { } } - // Now check existing auth roles for the user. Not all Auth Providers provider roles. + // Now check existing auth roles for the user. Not all Auth Providers authProviderID roles. if (!foundMatchingRole) { Iterator itrAuthProviderRequiredSvcRoles = authProviderRequiredSvcRoles.iterator(); @@ -407,21 +406,21 @@ protected Boolean validateUserRoles(ServiceUser serviceUser, String userId) { /** - * Retrieve the list of valid role names for the specified auth provider (or NONE) + * Retrieve the list of valid role names for the specified auth authProviderID (or NONE) * for which a user must have have at least one to access the system. * - * @param authProvider + * @param authProviderID * @return */ @SuppressWarnings("unchecked") - protected List getSvcAppRoles(AuthProvider authProvider) { + protected List getSvcAppRoles(String authProviderID) { Session s = null; List result = null; try { s = sessionFactoryAuth.openSession(); Query query = s.createQuery("FROM SvcAppRole sar WHERE sar.authProvider = :authProvider OR sar.authProvider = NULL"); - query.setString("authProvider", authProvider.toString()); + query.setString("authProvider", authProviderID.toString()); result = (List) query.list(); result = (List) AuthHibernateUtils.cleanObject(result); @@ -524,7 +523,7 @@ private UserAccount updateUserAccountToken(UserAccount theQueryObject, Boolean c theFoundUserAccount = new UserAccount(); - theFoundUserAccount.setAuthProvider(serviceUser.getAuthProvider()); + theFoundUserAccount.setAuthProviderID(serviceUser.getAuthProviderID()); theFoundUserAccount.setUser(theUser); theFoundUserAccount.setDateCreated(currentDate); theFoundUserAccount.setDateModified(currentDate); @@ -872,7 +871,7 @@ public List getServiceUsers(String aUserId) { // Get list of all ServiceApplicationOAuth's for this ServiceProvider. for (UserAccount nextUserAccount : userAccounts) { - ServiceUser nextServiceUser = getServiceProviderServiceUser(nextUserAccount, nextUserAccount.getAuthProvider()); + ServiceUser nextServiceUser = getServiceProviderServiceUser(nextUserAccount, nextUserAccount.getAuthProviderID()); if(nextServiceUser != null) { // Found a valid Service User, add to list and break. result.add(nextServiceUser); @@ -926,8 +925,8 @@ public Set getUserAccounts(String aUserId) { * @param aUserAccount * @return */ - public ServiceUser getServiceProviderServiceUser(UserAccount aUserAccount, AuthProvider provider) { - return getServiceProviderServiceUser(aUserAccount.getAccessToken(), aUserAccount.getRefreshToken(), aUserAccount.getAccountId(), provider); + public ServiceUser getServiceProviderServiceUser(UserAccount aUserAccount, String authProviderID) { + return getServiceProviderServiceUser(aUserAccount.getAccessToken(), aUserAccount.getRefreshToken(), aUserAccount.getAccountId(), authProviderID); } /** @@ -936,10 +935,10 @@ public ServiceUser getServiceProviderServiceUser(UserAccount aUserAccount, AuthP * @param accessToken * @param refreshToken * @param accountId - * @param provider + * @param authProviderID * @return */ - public ServiceUser getServiceProviderServiceUser(String accessToken, String refreshToken, String accountId, AuthProvider provider) { + public ServiceUser getServiceProviderServiceUser(String accessToken, String refreshToken, String accountId, String authProviderID) { ServiceUser serviceUser = null; try { @@ -950,7 +949,7 @@ public ServiceUser getServiceProviderServiceUser(String accessToken, String refr serviceUser.setFirstName("ANON"); serviceUser.setLastName("ANON"); serviceUser.setId("ANON"); - serviceUser.setAuthProvider(AuthProvider.ANON); + serviceUser.setAuthProviderID(AuthProvider.ANON.toString()); serviceUser.setRefreshToken(anonAuthCode); List roles = new ArrayList(); @@ -965,7 +964,7 @@ public ServiceUser getServiceProviderServiceUser(String accessToken, String refr } } - /**if (AuthProvider.LINKEDIN.equals(provider)) { + /**if (AuthProvider.LINKEDIN.equals(authProviderID)) { // LinkedInHelper linkedInHelper = new LinkedInHelper(); // ServiceUser liServiceUser = linkedInHelper.getServiceUser( // svcOauth.getAppKey(), svcOauthSecret.getAppToken(), @@ -974,44 +973,44 @@ public ServiceUser getServiceProviderServiceUser(String accessToken, String refr // svcOauth.getServiceApplication().getAppDomain()); // serviceUser = liServiceUser; } - else */if (AuthProvider.FACEBOOK.equals(provider)) { + else */if (AuthProvider.FACEBOOK.equals(authProviderID)) { ServiceUser fbServiceUser = facebookHelper.getServiceUser( accessToken, accountId); serviceUser = fbServiceUser; } - else if (AuthProvider.GOOGLE.equals(provider)) { + else if (AuthProvider.GOOGLE.equals(authProviderID)) { ServiceUser glServiceUser = googleHelper.authenticateAccessToken(accessToken, refreshToken, accountId); //ServiceUser glServiceUser = googleHelper.retrieveServiceUser(accountId); serviceUser = glServiceUser; } - else if (AuthProvider.GITHUB.equals(provider)) { + else if (AuthProvider.GITHUB.equals(authProviderID)) { ServiceUser glServiceUser = githubHelper.getServiceUser(accessToken, refreshToken); serviceUser = glServiceUser; } - else if (AuthProvider.LINKEDIN.equals(provider)) { + else if (AuthProvider.LINKEDIN.equals(authProviderID)) { ServiceUser liServiceUser = linkedInHelper.getServiceUser(accessToken, refreshToken); serviceUser = liServiceUser; } - else if(AuthProvider.ANON.equals(provider)){ + 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.setAuthProvider(AuthProvider.ANON); + serviceUser.setAuthProviderID(AuthProvider.ANON.toString()); } else { - log.warn("ServiceProvider not yet supported: " + provider); + log.warn("ServiceProvider not yet supported: " + authProviderID); } } catch (Exception e) { e.printStackTrace(); } if (serviceUser != null) - serviceUser.setAuthProvider(provider); + 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 new file mode 100644 index 0000000..8cf4750 --- /dev/null +++ b/src/main/java/com/percero/agents/auth/services/AuthService2.java @@ -0,0 +1,321 @@ +package com.percero.agents.auth.services; + +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 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.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +/** + * This class handles AuthenticationRequest type authentication + */ +@Component +public class AuthService2 { + + private static Logger logger = Logger.getLogger(AuthService2.class); + + @Autowired + private AuthProviderRegistry authProviderRegistry; + + @Autowired + SessionFactory sessionFactoryAuth; + + public AuthenticationResponse authenticate(AuthenticationRequest request) throws IllegalArgumentException{ + if(!authProviderRegistry.hasProvider(request.getAuthProvider())) + throw new IllegalArgumentException(request.getAuthProvider()+" auth provider not found"); + + AuthenticationResponse response = new AuthenticationResponse(); + + IAuthProvider provider = authProviderRegistry.getProvider(request.getAuthProvider()); + + ServiceUser serviceUser = provider.authenticate(request.getCredential()); + + // Login successful + if(serviceUser != null) { + logger.info(provider.getID()+" Authentication success"); + serviceUser.setAuthProviderID(provider.getID()); // Set the provider ID just in case the provider didn't + UserAccount userAccount = getOrCreateUserAccount(serviceUser, provider, request); + + UserToken userToken = loginUserAccount(userAccount, request.getClientId(), request.getDeviceId()); + userToken = (UserToken) AuthHibernateUtils.cleanObject(userToken); + response.setResult(userToken); + } + + return response; + } + + /** + * Allows the user to re-login with the token stored on their device from a previous login + * @param request + * @return + */ + public AuthenticationResponse reauthenticate(ReauthenticationRequest request){ + AuthenticationResponse response = new AuthenticationResponse(); + + Session session = sessionFactoryAuth.getCurrentSession(); + UserToken userToken = (UserToken) session.createCriteria(UserToken.class) + .add(Restrictions.eq("token", request.getToken())) + .uniqueResult(); + + // TODO: add expiration to the token + if(userToken != null){ + userToken.setLastLogin(new Date()); + userToken.setClientId(request.getClientId()); + session.save(userToken); + userToken = (UserToken) AuthHibernateUtils.cleanObject(userToken); + response.setResult(userToken); + } + + return response; + } + + /** + * Find a UserAccount from a ServiceUser + * @param serviceUser + * @return + */ + private UserAccount findUserAccount(ServiceUser serviceUser){ + 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) userAccounts).size() > 0) { + // Found a valid UserAccount. + List userAccountList = (List) userAccounts; + theFoundUserAccount = (UserAccount) userAccountList.get(0); + } + + return theFoundUserAccount; + } + + /** + * Find a User from a ServiceUser + * @param serviceUser + * @return + */ + private User findUser(ServiceUser serviceUser){ + Session s = sessionFactoryAuth.openSession(); + + User theUser = null; + + // Attempt to find this user by finding a matching UserIdentifier. + if (serviceUser.getIdentifiers() != null && serviceUser.getIdentifiers().size() > 0) { + String strFindUserIdentifier = "SELECT ui.user FROM UserIdentifier ui WHERE"; + int counter = 0; + for(ServiceIdentifier nextServiceIdentifier : serviceUser.getIdentifiers()) { + if (counter > 0) + strFindUserIdentifier += " OR "; + strFindUserIdentifier += " ui.type='" + nextServiceIdentifier.getParadigm() + "' AND ui.userIdentifier='" + nextServiceIdentifier.getValue() + "'"; + counter++; + } + + Query q = s.createQuery(strFindUserIdentifier); + List userList = (List) q.list(); + if (userList.size() > 0) { + theUser = userList.get(0); + } + } + + return theUser; + } + + /** + * Does the work of synchronizing the ServiceUser (from 3rd party) with the UserAccounts + * that ActiveStack knows about. + * @param serviceUser + * @returns UserAccount + */ + private UserAccount getOrCreateUserAccount(ServiceUser serviceUser, IAuthProvider provider, AuthenticationRequest request){ + + UserAccount theFoundUserAccount = null; + Session s = null; + try { + theFoundUserAccount = findUserAccount(serviceUser); + + if(theFoundUserAccount == null) { + s = sessionFactoryAuth.openSession(); + + User theUser = findUser(serviceUser); + + Transaction tx = s.beginTransaction(); + tx.begin(); + Date currentDate = new Date(); + + if (theUser == null) { + theUser = new User(); + theUser.setID(UUID.randomUUID().toString()); + theUser.setDateCreated(currentDate); + theUser.setDateModified(currentDate); + s.save(theUser); + } + + theFoundUserAccount = new UserAccount(); + + theFoundUserAccount.setAuthProviderID(serviceUser.getAuthProviderID()); + theFoundUserAccount.setUser(theUser); + theFoundUserAccount.setDateCreated(currentDate); + theFoundUserAccount.setDateModified(currentDate); + theFoundUserAccount.setAccountId(serviceUser.getId()); + + s.save(theFoundUserAccount); + tx.commit(); + + s.close(); + s = sessionFactoryAuth.openSession(); + + theFoundUserAccount = (UserAccount) s.get(UserAccount.class, + theFoundUserAccount.getID()); + } + + theFoundUserAccount = (UserAccount) AuthHibernateUtils + .cleanObject(theFoundUserAccount); + + // 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; + for(ServiceIdentifier nextServiceIdentifier : serviceUser.getIdentifiers()) { + q = s.createQuery("FROM UserIdentifier ui WHERE ui.userIdentifier=:uid AND ui.type=:paradigm"); + q.setString("uid", nextServiceIdentifier.getValue()); + q.setString("paradigm", nextServiceIdentifier.getParadigm()); + + List userIdenditifierList = (List) q.list(); + + if (userIdenditifierList.size() == 0) { + try { + UserIdentifier userIdentifier = new UserIdentifier(); + userIdentifier.setType(nextServiceIdentifier.getParadigm()); + userIdentifier.setUser(theFoundUserAccount.getUser()); + userIdentifier.setUserIdentifier(nextServiceIdentifier.getValue()); + s.saveOrUpdate(userIdentifier); + } catch(Exception e) { + logger.warn("Unable to save UserIdentifier for " + serviceUser.getName(), e); + } + } + } + tx.commit(); + } + } catch (Exception e) { + logger.error("Unable to run getOrCreateUserAccount", e); + } finally { + if (s != null) + s.close(); + } + return theFoundUserAccount; + } + + @SuppressWarnings("rawtypes") + private UserToken loginUserAccount(UserAccount theUserAccount, String clientId, String deviceId) { + Session s = null; + UserToken theUserToken = null; + try { + Date currentDate = new Date(); + UserToken queryUserToken = new UserToken(); + queryUserToken.setUser(theUserAccount.getUser()); + queryUserToken.setClientId(clientId); + List userTokenResult = findByExample(queryUserToken, null); + + if ( !userTokenResult.isEmpty() ) { + theUserToken = (UserToken) userTokenResult.get(0); + } + + if (s == null) + s = sessionFactoryAuth.openSession(); + Transaction tx = s.beginTransaction(); + tx.begin(); + + if (theUserToken == null) { + if (StringUtils.hasText(deviceId)) { + // Need to delete all of UserTokens for this User/Device. + logger.debug("Deleting ALL UserToken's for User " + theUserAccount.getUser().getID() + ", Device " + deviceId); + String deleteUserTokenSql = "DELETE FROM UserToken WHERE deviceId=:deviceId AND user=:user"; + Query deleteQuery = s.createQuery(deleteUserTokenSql); + deleteQuery.setString("deviceId", deviceId); + deleteQuery.setEntity("user", theUserAccount.getUser()); + deleteQuery.executeUpdate(); + } + + theUserToken = new UserToken(); + theUserToken.setUser(theUserAccount.getUser()); + theUserToken.setClientId(clientId); + theUserToken.setDeviceId(deviceId); + theUserToken.setDateCreated(currentDate); + theUserToken.setDateModified(currentDate); + theUserToken.setToken(getRandomId()); + theUserToken.setLastLogin(currentDate); + s.save(theUserToken); + + } else { + theUserToken.setToken(getRandomId()); + theUserToken.setLastLogin(currentDate); + //s.merge(theUserToken); + s.saveOrUpdate(theUserToken); + } + + tx.commit(); + + } catch (LockAcquisitionException lae) { + logger.error("Unable to run authenticate UserAccount", lae); + } catch (Exception e) { + logger.error("Unable to run authenticate UserAccount", e); + } finally { + if (s != null) + s.close(); + } + + 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(); + } +} diff --git a/src/main/java/com/percero/agents/auth/services/DatabaseHelper.java b/src/main/java/com/percero/agents/auth/services/DatabaseHelper.java index afcdcf9..0432696 100644 --- a/src/main/java/com/percero/agents/auth/services/DatabaseHelper.java +++ b/src/main/java/com/percero/agents/auth/services/DatabaseHelper.java @@ -56,7 +56,7 @@ public ServiceUser getServiceUser(String userName, String password) { result.getEmails().add(userIdentifier.getUserIdentifier()); } result.setAccessToken(UUID.randomUUID().toString()); - result.setAuthProvider(AuthProvider.DATABASE); + result.setAuthProviderID(AuthProvider.DATABASE.toString()); result.setAreRoleNamesAccurate(false); } 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 dc58ddb..7262383 100644 --- a/src/main/java/com/percero/agents/auth/services/GoogleHelper.java +++ b/src/main/java/com/percero/agents/auth/services/GoogleHelper.java @@ -184,7 +184,7 @@ public ServiceUser authenticateOAuthCode(String code, String redirectUri) throws ServiceUser serviceUser = new ServiceUser(); serviceUser.setAccessToken("DEV"); serviceUser.setAreRoleNamesAccurate(useRoleNames); - serviceUser.setAuthProvider(null); + serviceUser.setAuthProviderID(null); serviceUser.setAvatarUrl(""); ArrayList emails = new ArrayList(); @@ -268,7 +268,7 @@ private ServiceUser authenticateAccessToken(String accessToken, String refreshTo ServiceUser serviceUser = new ServiceUser(); serviceUser.setAccessToken("DEV"); serviceUser.setAreRoleNamesAccurate(useRoleNames); - serviceUser.setAuthProvider(null); + serviceUser.setAuthProviderID(null); serviceUser.setAvatarUrl(""); ArrayList emails = new ArrayList(); diff --git a/src/main/java/com/percero/agents/auth/services/IAuthProvider.java b/src/main/java/com/percero/agents/auth/services/IAuthProvider.java new file mode 100644 index 0000000..5b32aad --- /dev/null +++ b/src/main/java/com/percero/agents/auth/services/IAuthProvider.java @@ -0,0 +1,22 @@ +package com.percero.agents.auth.services; + +import com.percero.agents.auth.vo.ServiceUser; + +/** + * Defines the interface for providing additional authentication behavior into the ActiveStack + */ +public interface IAuthProvider { + /** + * Returns the string that uniquely identifies this provider + * @return String + */ + String getID(); + + /** + * Authenticates a token and returns a ServiceUser that cooresponds to the credentials provided + * @param credential - A String to be interpreted by the provider as an authentication credential + * @return ServiceUser + */ + ServiceUser authenticate(String credential); + +} 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 6687646..00e3bc0 100644 --- a/src/main/java/com/percero/agents/auth/services/IAuthService.java +++ b/src/main/java/com/percero/agents/auth/services/IAuthService.java @@ -21,7 +21,7 @@ public interface IAuthService { /** * Authenticates an OAuth Code. Typical use case is client-side code produces an OAuth Code that the server then valdates. * - * @param authProvider + * @param authProviderID * @param code * @param clientId * @param deviceId @@ -29,12 +29,12 @@ public interface IAuthService { * @param requestToken * @return */ - public OAuthResponse authenticateOAuthCode(AuthProvider authProvider, String code, String clientId, String deviceId, String redirectUrl, OAuthToken requestToken); + public OAuthResponse authenticateOAuthCode(String authProviderID, String code, String clientId, String deviceId, String redirectUrl, OAuthToken requestToken); /** * In the case the OAuth Provider allows exchanging a user name/password combination for an Access Token, this method does just that. * - * @param authProvider + * @param authProviderID * @param userName * @param password * @param scopes @@ -44,20 +44,20 @@ public interface IAuthService { * @param requestToken * @return */ - public OAuthResponse authenticateBasicOAuth(AuthProvider authProvider, String userName, String password, String scopes, String appUrl, String clientId, String deviceId, OAuthToken requestToken); + public OAuthResponse authenticateBasicOAuth(String authProviderID, String userName, String password, String scopes, String appUrl, String clientId, String deviceId, OAuthToken requestToken); /** * Authenticates an OAuth Access Token. Typically, OAuth providers issue an AccessToken (and RefreshToken) that can be used to authenticate * a user for a pre-determined amount of time. * - * @param authProvider + * @param authProviderID * @param accessToken * @param refreshToken * @param clientId * @param deviceId * @return */ - public OAuthResponse authenticateOAuthAccessToken(AuthProvider authProvider, String accessToken, String refreshToken, String clientId, String deviceId); + public OAuthResponse authenticateOAuthAccessToken(String authProviderID, String accessToken, String refreshToken, String clientId, String deviceId); /** * Checks to see if the aUserId, aToken, aClientId combination exists in the Auth Service data store. diff --git a/src/main/java/com/percero/agents/auth/vo/AuthRequest.java b/src/main/java/com/percero/agents/auth/vo/AuthRequest.java index 80bd0b1..ae3cd7e 100644 --- a/src/main/java/com/percero/agents/auth/vo/AuthRequest.java +++ b/src/main/java/com/percero/agents/auth/vo/AuthRequest.java @@ -67,11 +67,11 @@ public String getRegAppKey() { return regAppKey; } - private AuthProvider authProvider; - public AuthProvider getAuthProvider() { + private String authProvider; + public String getAuthProvider() { return authProvider; } - public void setAuthProvider(AuthProvider authProvider) { - this.authProvider = authProvider; + public void setAuthProvider(String authProviderID) { + this.authProvider = authProviderID; } } diff --git a/src/main/java/com/percero/agents/auth/vo/AuthenticationRequest.java b/src/main/java/com/percero/agents/auth/vo/AuthenticationRequest.java index 5998d12..1c26300 100644 --- a/src/main/java/com/percero/agents/auth/vo/AuthenticationRequest.java +++ b/src/main/java/com/percero/agents/auth/vo/AuthenticationRequest.java @@ -1,7 +1,5 @@ package com.percero.agents.auth.vo; -import java.util.Map; - /** * This class represents a request from the client where they will specify the provider name * that they wish to authenticate against and a credential string that the provider will @@ -9,14 +7,6 @@ */ public class AuthenticationRequest extends AuthRequest { - private String providerName; - public String getProviderName() { - return providerName; - } - public void setProviderName(String providerName) { - this.providerName = providerName; - } - private String credential; public String getCredential() { return credential; @@ -25,11 +15,4 @@ public void setCredential(String credential) { this.credential = credential; } - private Map context; - public Map getContext() { - return context; - } - public void setContext(Map context) { - this.context = context; - } } diff --git a/src/main/java/com/percero/agents/auth/vo/AuthenticationResponse.java b/src/main/java/com/percero/agents/auth/vo/AuthenticationResponse.java new file mode 100644 index 0000000..4121cf3 --- /dev/null +++ b/src/main/java/com/percero/agents/auth/vo/AuthenticationResponse.java @@ -0,0 +1,16 @@ +package com.percero.agents.auth.vo; + +/** + * Created by jonnysamps on 8/17/15. + */ +public class AuthenticationResponse extends AuthResponse { + + private UserToken result; + public UserToken getResult() { + return result; + } + public void setResult(UserToken result) { + this.result = result; + } + +} diff --git a/src/main/java/com/percero/agents/auth/vo/ReauthenticationRequest.java b/src/main/java/com/percero/agents/auth/vo/ReauthenticationRequest.java new file mode 100644 index 0000000..8cdd3e5 --- /dev/null +++ b/src/main/java/com/percero/agents/auth/vo/ReauthenticationRequest.java @@ -0,0 +1,9 @@ +package com.percero.agents.auth.vo; + +/** + * Intended to be used to re-establish a user session + * using the token rather than the OAuth accessToken + */ +public class ReauthenticationRequest extends AuthRequest{ + +} diff --git a/src/main/java/com/percero/agents/auth/vo/ServiceUser.java b/src/main/java/com/percero/agents/auth/vo/ServiceUser.java index ae58c7e..4b0d4a0 100644 --- a/src/main/java/com/percero/agents/auth/vo/ServiceUser.java +++ b/src/main/java/com/percero/agents/auth/vo/ServiceUser.java @@ -11,7 +11,7 @@ public class ServiceUser implements Serializable { */ private static final long serialVersionUID = 5880752591299642651L; - private AuthProvider authProvider; + private String authProvider; private String id = ""; private String login = ""; public String getLogin() { @@ -142,10 +142,10 @@ public String getAvatarUrl() { public void setAvatarUrl(String value) { avatarUrl = value; } - public AuthProvider getAuthProvider() { + public String getAuthProviderID() { return authProvider; } - public void setAuthProvider(AuthProvider authProvider) { - this.authProvider = authProvider; + public void setAuthProviderID(String authProviderID) { + this.authProvider = authProviderID; } } diff --git a/src/main/java/com/percero/agents/auth/vo/UserAccount.java b/src/main/java/com/percero/agents/auth/vo/UserAccount.java index 3299cbf..147765c 100644 --- a/src/main/java/com/percero/agents/auth/vo/UserAccount.java +++ b/src/main/java/com/percero/agents/auth/vo/UserAccount.java @@ -32,8 +32,8 @@ @Entity @Table(uniqueConstraints = { - @UniqueConstraint(columnNames={"authProvider", "accountId"}), - @UniqueConstraint(columnNames={"user_ID", "authProvider"}) + @UniqueConstraint(columnNames={"authProviderID", "accountId"}), + @UniqueConstraint(columnNames={"user_ID", "authProviderID"}) }) public class UserAccount extends _Super_UserAccount { diff --git a/src/main/java/com/percero/agents/auth/vo/_Super_UserAccount.java b/src/main/java/com/percero/agents/auth/vo/_Super_UserAccount.java index 65d8bc1..59daa72 100644 --- a/src/main/java/com/percero/agents/auth/vo/_Super_UserAccount.java +++ b/src/main/java/com/percero/agents/auth/vo/_Super_UserAccount.java @@ -9,8 +9,6 @@ import java.util.Date; import javax.persistence.Column; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; @@ -41,8 +39,7 @@ public class _Super_UserAccount implements Serializable, IAuthCachedObject private String _accountId; private Boolean _isSupended; private Boolean _isAdmin; - @Enumerated(EnumType.STRING) - private AuthProvider _authProvider; + private String _authProviderID; /* * Property getters and setters @@ -203,12 +200,12 @@ public int hashCode() return result; } - public AuthProvider getAuthProvider() { - return _authProvider; + public String getAuthProviderID() { + return _authProviderID; } - public void setAuthProvider(AuthProvider _provider) { - this._authProvider = _provider; + public void setAuthProviderID(String providerID) { + this._authProviderID = providerID; } } diff --git a/src/main/java/com/percero/agents/sync/access/AccessManager.java b/src/main/java/com/percero/agents/sync/access/AccessManager.java index 33b1fae..77440c0 100644 --- a/src/main/java/com/percero/agents/sync/access/AccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/AccessManager.java @@ -1257,6 +1257,34 @@ public String validateAndRetrieveCurrentClientId(String clientId, return null; } + @Override + public void updateWatcherFields(String category, String subCategory, + String fieldName, Collection fieldsToWatch, String[] params) { + // TODO Auto-generated method stub + + } + + @Override + public void addWatcherField(String category, String subCategory, + String fieldName, Collection collection, String[] params) { + // TODO Auto-generated method stub + + } + + @Override + public void addWatcherField(String category, String subCategory, + String fieldName, Collection collection) { + // TODO Auto-generated method stub + + } + + @Override + public void updateWatcherFields(String category, String subCategory, + String fieldName, Collection fieldsToWatch) { + // TODO Auto-generated method stub + + } + /* (non-Javadoc) * @see com.com.percero.agents.sync.services.IAccessManager#removeDeleteJournals(java.util.List) * diff --git a/src/main/java/com/percero/agents/sync/access/IAccessManager.java b/src/main/java/com/percero/agents/sync/access/IAccessManager.java index 7875993..0a20947 100644 --- a/src/main/java/com/percero/agents/sync/access/IAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/IAccessManager.java @@ -196,10 +196,14 @@ public Set findClientByUserIdDeviceId(String deviceId, String userId) //////////////////////////////////////////////////////// public void addWatcherField(ClassIDPair classIdPair, String fieldName, Collection collection); public void addWatcherField(ClassIDPair classIdPair, String fieldName, Collection collection, String[] params); + public void addWatcherField(String category, String subCategory, String fieldName, Collection collection); + public void addWatcherField(String category, String subCategory, String fieldName, Collection collection, String[] params); public void addWatcherClient(ClassIDPair classIdPair, String fieldName, String clientId); public void addWatcherClient(ClassIDPair classIdPair, String fieldName, String clientId, String[] params); public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Collection fieldsToWatch); public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Collection fieldsToWatch, String[] params); + public void updateWatcherFields(String category, String subCategory, String fieldName, Collection fieldsToWatch); + public void updateWatcherFields(String category, String subCategory, String fieldName, Collection fieldsToWatch, String[] params); public void saveChangeWatcherResult(ClassIDPair classIdPair, String fieldName, Object result); public void saveChangeWatcherResult(ClassIDPair classIdPair, String fieldName, Object result, String[] params); public Boolean getChangeWatcherResultExists(ClassIDPair classIdPair, String fieldName); diff --git a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java index cdcc43b..86bc1f0 100644 --- a/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java +++ b/src/main/java/com/percero/agents/sync/access/RedisAccessManager.java @@ -26,7 +26,7 @@ import com.percero.agents.sync.cw.ChangeWatcherReporting; import com.percero.agents.sync.cw.IChangeWatcherHelper; import com.percero.agents.sync.cw.IChangeWatcherHelperFactory; -import com.percero.agents.sync.datastore.RedisDataStore; +import com.percero.agents.sync.datastore.ICacheDataStore; import com.percero.agents.sync.exceptions.ClientException; import com.percero.agents.sync.helpers.RedisPostClientHelper; import com.percero.agents.sync.services.IPushSyncHelper; @@ -75,9 +75,9 @@ public void setPostClientHelper(RedisPostClientHelper value) { //MongoOperations mongoOperations; @Autowired - RedisDataStore redisDataStore; - public void setRedisDataStore(RedisDataStore redisDataStore) { - this.redisDataStore = redisDataStore; + ICacheDataStore cacheDataStore; + public void setCacheDataStore(ICacheDataStore cacheDataStore) { + this.cacheDataStore = cacheDataStore; } @Autowired @@ -105,48 +105,48 @@ public void setPushSyncHelper(IPushSyncHelper pushSyncHelper) { public void createClient(String clientId, String userId, String deviceType, String deviceId) throws Exception { String clientUserKey = RedisKeyUtils.clientUser(userId); - redisDataStore.addSetValue(clientUserKey, clientId); + cacheDataStore.addSetValue(clientUserKey, clientId); if (StringUtils.hasText(deviceId)) { String userDeviceKey = RedisKeyUtils.userDeviceHash(userId); - redisDataStore.setHashValue(userDeviceKey, deviceId, clientId); + cacheDataStore.setHashValue(userDeviceKey, deviceId, clientId); String deviceKey = RedisKeyUtils.deviceHash(deviceId); - redisDataStore.addSetValue(deviceKey, clientId); + cacheDataStore.addSetValue(deviceKey, clientId); } // Set the client's userId. - redisDataStore.setValue(RedisKeyUtils.client(clientId), userId); + cacheDataStore.setValue(RedisKeyUtils.client(clientId), userId); // Add to ClientUser list - redisDataStore.addSetValue(clientUserKey, clientId); + cacheDataStore.addSetValue(clientUserKey, clientId); if (Client.PERSISTENT_TYPE.equalsIgnoreCase(deviceType)) { - redisDataStore.addSetValue(RedisKeyUtils.clientsPersistent(), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientsPersistent(), clientId); } else { - redisDataStore.addSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); } } public Boolean isNonPersistentClient(String clientId) { - return redisDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId); + return cacheDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId); } public String getClientUserId(String clientId) { - return (String) redisDataStore.getValue(RedisKeyUtils.client(clientId)); + return (String) cacheDataStore.getValue(RedisKeyUtils.client(clientId)); } public Boolean findClientByClientIdUserId(String clientId, String userId) throws Exception { - return redisDataStore.getSetIsMember(RedisKeyUtils.clientUser(userId), clientId); + return cacheDataStore.getSetIsMember(RedisKeyUtils.clientUser(userId), clientId); } @SuppressWarnings("unchecked") public Set findClientByUserIdDeviceId(String userId, String deviceId) throws Exception { - Set deviceClientIds = (Set) redisDataStore.getSetValue(RedisKeyUtils.deviceHash(deviceId)); + Set deviceClientIds = (Set) cacheDataStore.getSetValue(RedisKeyUtils.deviceHash(deviceId)); if (deviceClientIds == null) { deviceClientIds = new HashSet(1); } - String result = (String) redisDataStore.getHashValue(RedisKeyUtils.userDeviceHash(userId), deviceId); + String result = (String) cacheDataStore.getHashValue(RedisKeyUtils.userDeviceHash(userId), deviceId); if (!StringUtils.hasText(result)) { deviceClientIds.add(result); } @@ -155,9 +155,9 @@ public Set findClientByUserIdDeviceId(String userId, String deviceId) th } public Boolean findClientByClientId(String clientId) { - if (redisDataStore.getSetIsMember(RedisKeyUtils.clientsPersistent(), clientId)) + if (cacheDataStore.getSetIsMember(RedisKeyUtils.clientsPersistent(), clientId)) return true; - else if (redisDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId)) + else if (cacheDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId)) return true; else return false; @@ -186,13 +186,13 @@ public Boolean validateClientByClientId(String clientId, Boolean setClientTimeou @SuppressWarnings("unchecked") public Set validateClients(Collection clientIds) throws Exception { - Set validClients = (Set) redisDataStore.getSetsContainsMembers(CLIENT_KEYS_SEY, clientIds.toArray()); + Set validClients = (Set) cacheDataStore.getSetsContainsMembers(CLIENT_KEYS_SEY, clientIds.toArray()); return validClients; } @SuppressWarnings("unchecked") public Set validateClientsIncludeFromDeviceHistory(Map clientDevices) throws Exception { - Set validClients = (Set) redisDataStore.getSetsContainsMembers(CLIENT_KEYS_SEY, clientDevices.keySet().toArray()); + Set validClients = (Set) cacheDataStore.getSetsContainsMembers(CLIENT_KEYS_SEY, clientDevices.keySet().toArray()); // Now check each device to see if it has a corresponding clientId. Iterator> itrClientDevices = clientDevices.entrySet().iterator(); @@ -201,7 +201,7 @@ public Set validateClientsIncludeFromDeviceHistory(Map c String nextClient = nextClientDevice.getKey(); String nextDevice = nextClientDevice.getValue(); - if (redisDataStore.getSetIsMember(RedisKeyUtils.deviceHash(nextDevice), nextClient)) { + if (cacheDataStore.getSetIsMember(RedisKeyUtils.deviceHash(nextDevice), nextClient)) { validClients.add(nextClient); } } @@ -217,9 +217,9 @@ public String validateAndRetrieveCurrentClientId(String clientId, String deviceI } else { // Client is NOT current, but could still be valid. - if (redisDataStore.getSetIsMember(RedisKeyUtils.deviceHash(deviceId), clientId)) { + if (cacheDataStore.getSetIsMember(RedisKeyUtils.deviceHash(deviceId), clientId)) { // Client IS valid, now get current Client. - Set validDeviceClientIds = (Set) redisDataStore.getSetValue(RedisKeyUtils.deviceHash(deviceId)); + Set validDeviceClientIds = (Set) cacheDataStore.getSetValue(RedisKeyUtils.deviceHash(deviceId)); Iterator itrValidDeviceClientIds = validDeviceClientIds.iterator(); while (itrValidDeviceClientIds.hasNext()) { String nextClientId = itrValidDeviceClientIds.next(); @@ -250,8 +250,8 @@ public void registerClient(String clientId, String userId, String deviceId, Stri if (!isValidClient) createClient(clientId, userId, deviceType, deviceId); - redisDataStore.addSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); - redisDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); + cacheDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); postClient(clientId); } @@ -263,8 +263,8 @@ public Boolean hibernateClient(String clientId, String userId) throws Exception // Make sure this client/user combo is a valid one. if (findClientByClientIdUserId(clientId, userId)) { // Remove the client from the LoggedIn list and add it to the Hibernated list. - redisDataStore.setHashValue(RedisKeyUtils.clientsHibernated(), clientId, System.currentTimeMillis()); - redisDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); + cacheDataStore.setHashValue(RedisKeyUtils.clientsHibernated(), clientId, System.currentTimeMillis()); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); // NOTE: The client is still in either the "client persistent" or "client non-persistent" list and // is therefore still considered a valid client. @@ -294,16 +294,16 @@ public Boolean upgradeClient(String clientId, String deviceId, String deviceType try { // Remove from NonPersistent list. - redisDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); // Add to Persistent List. - redisDataStore.addSetValue(RedisKeyUtils.clientsPersistent(), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientsPersistent(), clientId); // Add to LoggedIn list - redisDataStore.addSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); // Remove from Hibernated list - redisDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); + cacheDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); if (previousClientIds != null && !previousClientIds.isEmpty()) { Iterator itrPreviousClientIds = previousClientIds.iterator(); @@ -311,7 +311,7 @@ public Boolean upgradeClient(String clientId, String deviceId, String deviceType String nextPreviousClient = itrPreviousClientIds.next(); if (StringUtils.hasText(nextPreviousClient) && nextPreviousClient.equals(clientId)) { // Remove from NonPersistent list. - redisDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), nextPreviousClient); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), nextPreviousClient); renameClient(nextPreviousClient, clientId); } @@ -319,7 +319,7 @@ public Boolean upgradeClient(String clientId, String deviceId, String deviceType } else { // Add to ClientUser list - redisDataStore.addSetValue(RedisKeyUtils.clientUser(userId), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientUser(userId), clientId); } result = true; @@ -344,94 +344,94 @@ else if (thePreviousClient.equals(clientId)) { } // Get the existing UserId. - String userId = (String) redisDataStore.getValue(RedisKeyUtils.client(thePreviousClient)); + String userId = (String) cacheDataStore.getValue(RedisKeyUtils.client(thePreviousClient)); log.debug("Renaming client " + thePreviousClient + " to " + clientId); if (StringUtils.hasText(userId)) { log.debug("Renaming user " + userId + " from client " + thePreviousClient + " to " + clientId); // Remove Previous Client from ClientUser list - redisDataStore.removeSetValue(RedisKeyUtils.clientUser(userId), thePreviousClient); + cacheDataStore.removeSetValue(RedisKeyUtils.clientUser(userId), thePreviousClient); // Add to ClientUser list - redisDataStore.addSetValue(RedisKeyUtils.clientUser(userId), clientId); + cacheDataStore.addSetValue(RedisKeyUtils.clientUser(userId), clientId); // Update the UserDevice ClientID. String userDeviceHashKey = RedisKeyUtils.userDeviceHash(userId); - Collection userDeviceKeys = redisDataStore.getHashKeys(userDeviceHashKey); + Collection userDeviceKeys = cacheDataStore.getHashKeys(userDeviceHashKey); Iterator itrUserDevices = userDeviceKeys.iterator(); while (itrUserDevices.hasNext()) { String nextDeviceKey = (String) itrUserDevices.next(); - if (thePreviousClient.equals(redisDataStore.getHashValue(userDeviceHashKey, nextDeviceKey))) { - redisDataStore.addSetValue(RedisKeyUtils.deviceHash(nextDeviceKey), clientId); - redisDataStore.setHashValue(userDeviceHashKey, nextDeviceKey, clientId); + if (thePreviousClient.equals(cacheDataStore.getHashValue(userDeviceHashKey, nextDeviceKey))) { + cacheDataStore.addSetValue(RedisKeyUtils.deviceHash(nextDeviceKey), clientId); + cacheDataStore.setHashValue(userDeviceHashKey, nextDeviceKey, clientId); } } // Set the Client's userId - redisDataStore.setValue(RedisKeyUtils.client(clientId), userId); + cacheDataStore.setValue(RedisKeyUtils.client(clientId), userId); // Remove the Previous Client's userId - redisDataStore.deleteKey(RedisKeyUtils.client(thePreviousClient)); + cacheDataStore.deleteKey(RedisKeyUtils.client(thePreviousClient)); } else { log.debug("Previous Client" + thePreviousClient + " has no corresponding UserID"); } // Swap NonPersistent list. - redisDataStore.swapSetValue(RedisKeyUtils.clientsNonPersistent(), thePreviousClient, clientId); + cacheDataStore.swapSetValue(RedisKeyUtils.clientsNonPersistent(), thePreviousClient, clientId); // Swap Persistent list. - redisDataStore.swapSetValue(RedisKeyUtils.clientsPersistent(), thePreviousClient, clientId); + cacheDataStore.swapSetValue(RedisKeyUtils.clientsPersistent(), thePreviousClient, clientId); // Swap LoggedIn list. - redisDataStore.swapSetValue(RedisKeyUtils.clientsLoggedIn(), thePreviousClient, clientId); + cacheDataStore.swapSetValue(RedisKeyUtils.clientsLoggedIn(), thePreviousClient, clientId); // Swap Hibernated list. - redisDataStore.swapHashKey(RedisKeyUtils.clientsHibernated(), thePreviousClient, clientId); + cacheDataStore.swapHashKey(RedisKeyUtils.clientsHibernated(), thePreviousClient, clientId); // Rename the UpdateJournals list. String prevUpdateJournalKey = RedisKeyUtils.updateJournal(thePreviousClient); - if (redisDataStore.hasKey(prevUpdateJournalKey)) { - if (!redisDataStore.renameIfAbsent(prevUpdateJournalKey, RedisKeyUtils.updateJournal(clientId))) { + if (cacheDataStore.hasKey(prevUpdateJournalKey)) { + if (!cacheDataStore.renameIfAbsent(prevUpdateJournalKey, RedisKeyUtils.updateJournal(clientId))) { // If new list already exists, then merge the two. - redisDataStore.setUnionAndStore(RedisKeyUtils.updateJournal(thePreviousClient), RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.updateJournal(clientId)); + cacheDataStore.setUnionAndStore(RedisKeyUtils.updateJournal(thePreviousClient), RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.updateJournal(clientId)); // Delete the old Key - redisDataStore.deleteKey(RedisKeyUtils.updateJournal(thePreviousClient)); + cacheDataStore.deleteKey(RedisKeyUtils.updateJournal(thePreviousClient)); } } // Rename the DeleteJournals list. String prevDeleteJournalKey = RedisKeyUtils.deleteJournal(thePreviousClient); - if (redisDataStore.hasKey(prevDeleteJournalKey)) { - if (!redisDataStore.renameIfAbsent(RedisKeyUtils.deleteJournal(thePreviousClient), RedisKeyUtils.deleteJournal(clientId))) { + if (cacheDataStore.hasKey(prevDeleteJournalKey)) { + if (!cacheDataStore.renameIfAbsent(RedisKeyUtils.deleteJournal(thePreviousClient), RedisKeyUtils.deleteJournal(clientId))) { // If new list already exists, then merge the two. - redisDataStore.setUnionAndStore(RedisKeyUtils.deleteJournal(thePreviousClient), RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.deleteJournal(clientId)); + cacheDataStore.setUnionAndStore(RedisKeyUtils.deleteJournal(thePreviousClient), RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.deleteJournal(clientId)); // Delete the old Key - redisDataStore.deleteKey(RedisKeyUtils.deleteJournal(thePreviousClient)); + cacheDataStore.deleteKey(RedisKeyUtils.deleteJournal(thePreviousClient)); } } // Merge sets of Access Journals. String prevClientAccessJournalKey = RedisKeyUtils.clientAccessJournal(thePreviousClient); - if (redisDataStore.hasKey(prevClientAccessJournalKey)) { - Set accessJournalIds = (Set)redisDataStore.getSetValue(prevClientAccessJournalKey); + if (cacheDataStore.hasKey(prevClientAccessJournalKey)) { + Set accessJournalIds = (Set)cacheDataStore.getSetValue(prevClientAccessJournalKey); Iterator itrAccessJournalIds = accessJournalIds.iterator(); while (itrAccessJournalIds.hasNext()) { String nextAccessJournalId = itrAccessJournalIds.next(); - redisDataStore.swapSetValue(RedisKeyUtils.accessJournal(nextAccessJournalId), thePreviousClient, clientId); + cacheDataStore.swapSetValue(RedisKeyUtils.accessJournal(nextAccessJournalId), thePreviousClient, clientId); } } - redisDataStore.setUnionAndStore(RedisKeyUtils.clientAccessJournal(clientId), RedisKeyUtils.clientAccessJournal(thePreviousClient), RedisKeyUtils.clientAccessJournal(clientId)); + cacheDataStore.setUnionAndStore(RedisKeyUtils.clientAccessJournal(clientId), RedisKeyUtils.clientAccessJournal(thePreviousClient), RedisKeyUtils.clientAccessJournal(clientId)); // Merge sets of ChangeWatchers. String prevWatcherClientKey = RedisKeyUtils.watcherClient(thePreviousClient); - if (redisDataStore.hasKey(prevWatcherClientKey)) { - Set changeWatcherIds = (Set)redisDataStore.getSetValue(prevWatcherClientKey); + if (cacheDataStore.hasKey(prevWatcherClientKey)) { + Set changeWatcherIds = (Set)cacheDataStore.getSetValue(prevWatcherClientKey); Iterator itrChangeWatcherIds = changeWatcherIds.iterator(); while (itrChangeWatcherIds.hasNext()) { String nextChangeWatcherId = itrChangeWatcherIds.next(); - redisDataStore.swapSetValue(nextChangeWatcherId, thePreviousClient, clientId); + cacheDataStore.swapSetValue(nextChangeWatcherId, thePreviousClient, clientId); } } - redisDataStore.setUnionAndStore(RedisKeyUtils.watcherClient(clientId), RedisKeyUtils.watcherClient(thePreviousClient), RedisKeyUtils.watcherClient(clientId)); + cacheDataStore.setUnionAndStore(RedisKeyUtils.watcherClient(clientId), RedisKeyUtils.watcherClient(thePreviousClient), RedisKeyUtils.watcherClient(clientId)); // // Rename the TransactionJournals list. // Collection transKeys = redisDataStore.keys(RedisKeyUtils.transactionJournal(clientId, "*")); @@ -454,10 +454,10 @@ public void logoutClient(String clientId, Boolean pleaseDestroyClient) { log.debug("Logging out client " + clientId + " [" + (pleaseDestroyClient != null && pleaseDestroyClient ? "T" : "F") + "]"); // Remove from LoggedIn Clients - redisDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); // Check to see if this is a non-persistent client type. - Boolean isNonPersistent = redisDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId); + Boolean isNonPersistent = cacheDataStore.getSetIsMember(RedisKeyUtils.clientsNonPersistent(), clientId); if (isNonPersistent || pleaseDestroyClient) { destroyClient(clientId); @@ -468,7 +468,6 @@ public void logoutClient(String clientId, Boolean pleaseDestroyClient) { } } - @Override @Transactional public void destroyClient(String clientId) { if (!StringUtils.hasText(clientId)) { @@ -476,37 +475,37 @@ public void destroyClient(String clientId) { } // Get the client's userId. - String userId = (String) redisDataStore.getValue(RedisKeyUtils.client(clientId)); + String userId = (String) cacheDataStore.getValue(RedisKeyUtils.client(clientId)); Boolean validUser = StringUtils.hasText(userId); // Remove from ClientUser list if (validUser) { - redisDataStore.removeSetValue(RedisKeyUtils.clientUser(userId), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientUser(userId), clientId); } // Remove from Client's User ID. - redisDataStore.deleteKey(RedisKeyUtils.client(clientId)); + cacheDataStore.deleteKey(RedisKeyUtils.client(clientId)); // Remove from LoggedIn Clients - redisDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsLoggedIn(), clientId); // Remove from Hibernated Clients - redisDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); + cacheDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), clientId); // Remove from NonPersistent Clients - redisDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); // Remove from Persistent Clients - redisDataStore.removeSetValue(RedisKeyUtils.clientsPersistent(), clientId); + cacheDataStore.removeSetValue(RedisKeyUtils.clientsPersistent(), clientId); // Delete all UpdateJournals for this Client. String updateJournalKey = RedisKeyUtils.updateJournal(clientId); // Set updateJournalIds = (Set)redisDataStore.getSetValue(updateJournalKey); // redisDataStore.removeSetsValue(updateJournalIds, clientId); - redisDataStore.deleteKey(updateJournalKey); + cacheDataStore.deleteKey(updateJournalKey); // Delete all DeleteJournals for this Client. - redisDataStore.deleteKey(RedisKeyUtils.deleteJournal(clientId)); + cacheDataStore.deleteKey(RedisKeyUtils.deleteJournal(clientId)); // // Delete all TransactionJournals for this Client. // Collection transJournalKeys = redisDataStore.keys(RedisKeyUtils.transactionJournal(clientId, "*")); @@ -515,25 +514,25 @@ public void destroyClient(String clientId) { // Delete Client's UserDevice. if (validUser) { String userDeviceHashKey = RedisKeyUtils.userDeviceHash(userId); - Collection userDeviceKeys = redisDataStore.getHashKeys(userDeviceHashKey); + Collection userDeviceKeys = cacheDataStore.getHashKeys(userDeviceHashKey); int originalSize = userDeviceKeys.size(); int countRemoved = 0; Iterator itrUserDevices = userDeviceKeys.iterator(); while (itrUserDevices.hasNext()) { String nextDeviceKey = (String) itrUserDevices.next(); - if (clientId.equals(redisDataStore.getHashValue(userDeviceHashKey, nextDeviceKey))) { + if (clientId.equals(cacheDataStore.getHashValue(userDeviceHashKey, nextDeviceKey))) { // Since the client id being destroyed, the whole device history related to this client is also to be destroyed. // However, as a safety precaution, set the expiration for the device hash. - redisDataStore.expire(RedisKeyUtils.deviceHash(nextDeviceKey), userDeviceTimeout, TimeUnit.SECONDS); - redisDataStore.removeSetValue(RedisKeyUtils.deviceHash(nextDeviceKey), clientId); - redisDataStore.deleteHashKey(userDeviceHashKey, nextDeviceKey); + cacheDataStore.expire(RedisKeyUtils.deviceHash(nextDeviceKey), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.removeSetValue(RedisKeyUtils.deviceHash(nextDeviceKey), clientId); + cacheDataStore.deleteHashKey(userDeviceHashKey, nextDeviceKey); countRemoved++; } } if (countRemoved >= originalSize) { // Remove the UserDevice Hash. - redisDataStore.deleteKey(userDeviceHashKey); + cacheDataStore.deleteKey(userDeviceHashKey); } } @@ -573,22 +572,22 @@ public void destroyClient(String clientId) { @Transactional private void deleteClientAccessJournals(String clientId) { String clientAccessJournalsKey = RedisKeyUtils.clientAccessJournal(clientId); - Set clientAccessJournals = (Set) redisDataStore.getSetValue(clientAccessJournalsKey); - redisDataStore.removeSetsValue(RedisKeyUtils.ACCESS_JOURNAL_PREFIX, clientAccessJournals, clientId); + Set clientAccessJournals = (Set) cacheDataStore.getSetValue(clientAccessJournalsKey); + cacheDataStore.removeSetsValue(RedisKeyUtils.ACCESS_JOURNAL_PREFIX, clientAccessJournals, clientId); // Now remove the Client's AccessJournal key. - redisDataStore.deleteKey(clientAccessJournalsKey); + cacheDataStore.deleteKey(clientAccessJournalsKey); } @SuppressWarnings("unchecked") @Transactional private void deleteClientWatchers(String clientId) { String watcherClientKey = RedisKeyUtils.watcherClient(clientId); - Set watcherClientIds = (Set) redisDataStore.getSetValue(watcherClientKey); - redisDataStore.removeSetsValue("", watcherClientIds, clientId); + Set watcherClientIds = (Set) cacheDataStore.getSetValue(watcherClientKey); + cacheDataStore.removeSetsValue("", watcherClientIds, clientId); // Now remove the Client's Watcher key. - redisDataStore.deleteKey(watcherClientKey); + cacheDataStore.deleteKey(watcherClientKey); } /** @@ -619,7 +618,7 @@ public void postAccessJournals() { Iterator itrAccessJournals = accessJournalsToDelete.iterator(); while (itrAccessJournals.hasNext()) { String nextAccessJournal = itrAccessJournals.next(); - Set accessJournalClients = (Set)redisDataStore.getSetValue(nextAccessJournal); + Set accessJournalClients = (Set)cacheDataStore.getSetValue(nextAccessJournal); if (accessJournalClients != null) { Set clientIdsToRemove = new HashSet(); @@ -638,7 +637,7 @@ else if (!findClientByClientId(nextClientId) || !StringUtils.hasText(getClientUs } if (!clientIdsToRemove.isEmpty()) { - redisDataStore.removeSetValues(nextAccessJournal, clientIdsToRemove); + cacheDataStore.removeSetValues(nextAccessJournal, clientIdsToRemove); } } } @@ -689,7 +688,7 @@ public void postClients() { } // Now check Hibernating clients to see if any of those need to be removed - Map hibernatingClients = redisDataStore.getHashEntries(RedisKeyUtils.clientsHibernated()); + Map hibernatingClients = cacheDataStore.getHashEntries(RedisKeyUtils.clientsHibernated()); Iterator> itrHibernatingClientsEntries = hibernatingClients.entrySet().iterator(); while (itrHibernatingClientsEntries.hasNext()) { Map.Entry nextEntry = itrHibernatingClientsEntries.next(); @@ -699,7 +698,7 @@ public void postClients() { } catch(Exception e) { // This is an invalid key, so remove it from the hash. try { - redisDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), nextEntry.getKey()); + cacheDataStore.deleteHashKey(RedisKeyUtils.clientsHibernated(), nextEntry.getKey()); } catch(Exception e1) { log.error("Invalid hash key in " + RedisKeyUtils.clientsHibernated()); } @@ -712,7 +711,7 @@ public void postClients() { } catch(Exception e) { // This timeout is not in a valid format, set to current time and move on. try { - redisDataStore.setHashValue(RedisKeyUtils.clientsHibernated(), nextHibernatingClientId, nextEntry.getValue()); + cacheDataStore.setHashValue(RedisKeyUtils.clientsHibernated(), nextHibernatingClientId, nextEntry.getValue()); } catch(Exception e1) { log.error("Invalid hash value in " + RedisKeyUtils.clientsHibernated()); } @@ -758,7 +757,7 @@ public void saveUpdateJournalClients(ClassIDPair pair, Collection client } String key = RedisKeyUtils.updateJournal(nextClient); - redisDataStore.addSetValue(key, classValue); + cacheDataStore.addSetValue(key, classValue); } } catch(Exception e) { @@ -768,12 +767,12 @@ public void saveUpdateJournalClients(ClassIDPair pair, Collection client } public Long deleteUpdateJournal(String clientId, String className, String classId) { - return redisDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(className, classId)); + return cacheDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(className, classId)); } public void deleteUpdateJournals(String clientId, ClassIDPair[] objects) { for(ClassIDPair nextObject : objects) { - redisDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(nextObject.getClassName(), nextObject.getID())); + cacheDataStore.removeSetValue(RedisKeyUtils.updateJournal(clientId), RedisKeyUtils.classIdPair(nextObject.getClassName(), nextObject.getID())); } } @@ -791,7 +790,7 @@ public void saveDeleteJournalClients(ClassIDPair pair, Collection client } String key = RedisKeyUtils.deleteJournal(nextClient); - redisDataStore.addSetValue(key, classValue); + cacheDataStore.addSetValue(key, classValue); } } catch(Exception e) { @@ -801,12 +800,12 @@ public void saveDeleteJournalClients(ClassIDPair pair, Collection client } public Long deleteDeleteJournal(String clientId, String className, String classId) { - return redisDataStore.removeSetValue(RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.classIdPair(className, classId)); + return cacheDataStore.removeSetValue(RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.classIdPair(className, classId)); } public void deleteDeleteJournals(String clientId, ClassIDPair[] objects) { for(ClassIDPair nextObject : objects) { - redisDataStore.removeSetValue(RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.classIdPair(nextObject.getClassName(), nextObject.getID())); + cacheDataStore.removeSetValue(RedisKeyUtils.deleteJournal(clientId), RedisKeyUtils.classIdPair(nextObject.getClassName(), nextObject.getID())); } } @@ -829,10 +828,10 @@ private Long upsertRedisAccessJournal(String userId, String clientId, String cla try { // Need to add the ObjectID to the Client's AccessJournals set. String clientAccessJournalKey = RedisKeyUtils.clientAccessJournal(clientId); - redisDataStore.addSetValue(clientAccessJournalKey, RedisKeyUtils.objectId(className, classId)); + cacheDataStore.addSetValue(clientAccessJournalKey, RedisKeyUtils.objectId(className, classId)); // Need to add the ClientID to the Object's AccessJournal set. - return redisDataStore.addSetValue(key, clientId); + return cacheDataStore.addSetValue(key, clientId); } catch(Exception e) { log.error("Unable to upsertRedisAccessJournal", e); } finally { @@ -868,7 +867,7 @@ public List getObjectAccessJournals(String className, String classId) th //moveAccessJournals(); // TODO: Use a class id map instead of class name for faster lookup. // Use hash of full class name to generate ID? - Set redisClassIdSet = (Set) redisDataStore.getSetUnion(objectAccessJournalKey, allObjectAccessJournalKey); + Set redisClassIdSet = (Set) cacheDataStore.getSetUnion(objectAccessJournalKey, allObjectAccessJournalKey); result.addAll(redisClassIdSet); // RedisKeyUtils.accessJournal(className, classId), // RedisKeyUtils.accessJournal(className, "0")); @@ -901,15 +900,15 @@ public Collection getClientUpdateJournals(String clientId, Boolean logge Collection updateJournalSet = null; if (loggedInOnly) { - if (redisDataStore.getSetIsMember(RedisKeyUtils.clientsLoggedIn(), clientId)) { - updateJournalSet = (Set) redisDataStore.getSetValue(key); + if (cacheDataStore.getSetIsMember(RedisKeyUtils.clientsLoggedIn(), clientId)) { + updateJournalSet = (Set) cacheDataStore.getSetValue(key); } else { updateJournalSet = new HashSet(0); } } else { - updateJournalSet = (Set) redisDataStore.getSetValue(key); + updateJournalSet = (Set) cacheDataStore.getSetValue(key); } return updateJournalSet; @@ -924,15 +923,15 @@ public Collection getClientDeleteJournals(String clientId, Boolean logge Collection deleteJournalSet = null; if (loggedInOnly) { - if (redisDataStore.getSetIsMember(RedisKeyUtils.clientsLoggedIn(), clientId)) { - deleteJournalSet = (Set) redisDataStore.getSetValue(key); + if (cacheDataStore.getSetIsMember(RedisKeyUtils.clientsLoggedIn(), clientId)) { + deleteJournalSet = (Set) cacheDataStore.getSetValue(key); } else { deleteJournalSet = new HashSet(0); } } else { - deleteJournalSet = (Set) redisDataStore.getSetValue(key); + deleteJournalSet = (Set) cacheDataStore.getSetValue(key); } return deleteJournalSet; @@ -943,7 +942,7 @@ public Collection getClientDeleteJournals(String clientId, Boolean logge */ public void removeUpdateJournals(String clientId, Collection updateJournalsToRemove) throws Exception { String key = RedisKeyUtils.updateJournal(clientId); - redisDataStore.removeSetValues(key, updateJournalsToRemove); + cacheDataStore.removeSetValues(key, updateJournalsToRemove); } /* (non-Javadoc) @@ -959,7 +958,7 @@ public void removeAccessJournalsByObject(ClassIDPair classIdPair) { String objectId = RedisKeyUtils.objectId(classIdPair.getClassName(), classIdPair.getID()); String accessJournalKey = RedisKeyUtils.accessJournal(classIdPair.getClassName(), classIdPair.getID()); - Set clientIds = (Set) redisDataStore.getSetValue(accessJournalKey); + Set clientIds = (Set) cacheDataStore.getSetValue(accessJournalKey); Set clientAccessJournalKeys = new HashSet(clientIds.size()); Iterator itrClientIds = clientIds.iterator(); while (itrClientIds.hasNext()) { @@ -969,7 +968,7 @@ public void removeAccessJournalsByObject(ClassIDPair classIdPair) { clientAccessJournalKeys.add(clientAccessJournalsKey); } - redisDataStore.removeSetsValue(clientAccessJournalKeys, objectId); + cacheDataStore.removeSetsValue(clientAccessJournalKeys, objectId); // Iterator itrClientIds = clientIds.iterator(); // while (itrClientIds.hasNext()) { @@ -985,15 +984,15 @@ public void removeAccessJournalsByObject(ClassIDPair classIdPair) { // } // Now delete the AccessJournal record. - redisDataStore.deleteKey(accessJournalKey); + cacheDataStore.deleteKey(accessJournalKey); } public void removeObjectModJournalsByObject(ClassIDPair classIdPair) { - redisDataStore.deleteKey(RedisKeyUtils.objectModJournal(classIdPair.getClassName(), classIdPair.getID())); + cacheDataStore.deleteKey(RedisKeyUtils.objectModJournal(classIdPair.getClassName(), classIdPair.getID())); } public void removeHistoricalObjectsByObject(ClassIDPair classIdPair) { - redisDataStore.deleteKey(RedisKeyUtils.historicalObject(classIdPair.getClassName(), classIdPair.getID())); + cacheDataStore.deleteKey(RedisKeyUtils.historicalObject(classIdPair.getClassName(), classIdPair.getID())); } @@ -1012,11 +1011,17 @@ public void addWatcherField(ClassIDPair classIdPair, String fieldName, Collectio addWatcherField(classIdPair, fieldName, collection, null); } public void addWatcherField(ClassIDPair classIdPair, String fieldName, Collection collection, String[] params) { + addWatcherField(classIdPair.getClassName(), classIdPair.getID(), fieldName, collection, params); + } + public void addWatcherField(String category, String subCategory, String fieldName, Collection collection) { + addWatcherField(category, subCategory, fieldName, collection, null); + } + public void addWatcherField(String category, String subCategory, String fieldName, Collection collection, String[] params) { String fieldWatcherId = ""; if (params != null) - fieldWatcherId = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), classIdPair.getID(), fieldName, params)); + fieldWatcherId = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(category, subCategory, fieldName, params)); else - fieldWatcherId = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), fieldName)); + fieldWatcherId = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(category, subCategory, fieldName)); if (collection != null) collection.add(fieldWatcherId); } @@ -1035,33 +1040,41 @@ public void addWatcherClient(ClassIDPair classIdPair, String fieldName, String c changeWatcherId = RedisKeyUtils.clientWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), fieldName)); // Add the ClientID to the ChangeWatcher client Set - redisDataStore.addSetValue(changeWatcherId, clientId); + cacheDataStore.addSetValue(changeWatcherId, clientId); // Also add the ChangeWatcher ID to the client ChangeWatcher Set - redisDataStore.addSetValue(RedisKeyUtils.watcherClient(clientId), changeWatcherId); + cacheDataStore.addSetValue(RedisKeyUtils.watcherClient(clientId), changeWatcherId); } public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Collection fieldsToWatch) { updateWatcherFields(classIdPair, fieldName, fieldsToWatch, null); } + public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Collection fieldsToWatch, String[] params) { + updateWatcherFields(classIdPair.getClassName(), classIdPair.getID(), fieldName, fieldsToWatch, params); + } + + public void updateWatcherFields(String category, String subCategory, String fieldName, Collection fieldsToWatch) { + updateWatcherFields(category, subCategory, fieldName, fieldsToWatch, null); + } + @SuppressWarnings("unchecked") @Transactional - public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Collection fieldsToWatch, String[] params) { + public void updateWatcherFields(String category, String subCategory, String fieldName, Collection fieldsToWatch, String[] params) { String changeWatcherId = ""; String watcherField = ""; if (params != null) { - changeWatcherId = RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), classIdPair.getID(), fieldName, params); - watcherField = RedisKeyUtils.watcherField(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), fieldName)); + changeWatcherId = RedisKeyUtils.changeWatcherWithParams(category, subCategory, fieldName, params); + watcherField = RedisKeyUtils.watcherField(RedisKeyUtils.changeWatcher(category, subCategory, fieldName)); } else { - changeWatcherId = RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), fieldName); + changeWatcherId = RedisKeyUtils.changeWatcher(category, subCategory, fieldName); watcherField = RedisKeyUtils.watcherField(changeWatcherId); } - Collection watchedFields = (Set) redisDataStore.getSetValue(watcherField); + Collection watchedFields = (Set) cacheDataStore.getSetValue(watcherField); // Remove current set of fields to watch and replace with new set. - redisDataStore.replaceSet(watcherField, fieldsToWatch); + cacheDataStore.replaceSet(watcherField, fieldsToWatch); if (fieldsToWatch != null) { Iterator itrFieldsToWatch = fieldsToWatch.iterator(); @@ -1069,7 +1082,7 @@ public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Colle String nextField = itrFieldsToWatch.next(); // Also add this ChangeWatcher from the FieldWatcher. - redisDataStore.addSetValue(nextField, changeWatcherId); + cacheDataStore.addSetValue(nextField, changeWatcherId); // Keep track of field that is being watched at an object level. String[] nextFieldArr = nextField.split(":"); @@ -1091,7 +1104,7 @@ public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Colle } String objectWatchedFieldKey = RedisKeyUtils.objectWatchedFields(nextFieldClassName, nextFieldClassId); - redisDataStore.setHashValue(objectWatchedFieldKey, hashKey, nextField); + cacheDataStore.setHashValue(objectWatchedFieldKey, hashKey, nextField); } if (watchedFields != null) { @@ -1108,24 +1121,27 @@ public void updateWatcherFields(ClassIDPair classIdPair, String fieldName, Colle String nextOldField = itrOldWatchedFields.next(); // Also remove this ChangeWatcher from the FieldWatcher. - redisDataStore.removeSetValue(nextOldField, changeWatcherId); + cacheDataStore.removeSetValue(nextOldField, changeWatcherId); } } } - @SuppressWarnings("unchecked") public void removeChangeWatchersByObject(ClassIDPair classIdPair) { - String classKey = RedisKeyUtils.changeWatcherClass(classIdPair.getClassName(), classIdPair.getID()); + removeChangeWatchers(classIdPair.getClassName(), classIdPair.getID()); + } + @SuppressWarnings("unchecked") + public void removeChangeWatchers(String category, String subCategory) { + String categoryKey = RedisKeyUtils.changeWatcherClass(category, subCategory); // Get all change watcher values associated with this object. - Set changeWatcherValueKeys = redisDataStore.getHashKeys(classKey); + Set changeWatcherValueKeys = cacheDataStore.getHashKeys(categoryKey); Iterator itrChangeWatcherValueKeys = changeWatcherValueKeys.iterator(); while (itrChangeWatcherValueKeys.hasNext()) { String nextChangeWatcherValueKey = (String) itrChangeWatcherValueKeys.next(); // If this is a RESULT key, then add it to the list to check. if (nextChangeWatcherValueKey.endsWith(":" + RedisKeyUtils.RESULT)) { int resultIndex = nextChangeWatcherValueKey.lastIndexOf(":" + RedisKeyUtils.RESULT); - String changeWatcherKey = classKey + ":" + nextChangeWatcherValueKey.substring(0, resultIndex); + String changeWatcherKey = categoryKey + ":" + nextChangeWatcherValueKey.substring(0, resultIndex); String key = changeWatcherKey; String clientWatcherKey = RedisKeyUtils.clientWatcher(changeWatcherKey); @@ -1133,36 +1149,36 @@ public void removeChangeWatchersByObject(ClassIDPair classIdPair) { // For every watcherField, find the corresponding set and remove this changeWatcherKey // from that set. String watcherField = RedisKeyUtils.watcherField(changeWatcherKey); - Set watcherFieldValues = (Set) redisDataStore.getSetValue(watcherField); + Set watcherFieldValues = (Set) cacheDataStore.getSetValue(watcherField); Iterator itrWatcherFieldValues = watcherFieldValues.iterator(); while (itrWatcherFieldValues.hasNext()) { String nextWatcherFieldValue = itrWatcherFieldValues.next(); - redisDataStore.removeSetValue(nextWatcherFieldValue, changeWatcherKey); + cacheDataStore.removeSetValue(nextWatcherFieldValue, changeWatcherKey); } String fieldWatcher = RedisKeyUtils.fieldWatcher(changeWatcherKey); // Now remove all keys associated with this Change Watcher Value. - redisDataStore.deleteKey(key); - redisDataStore.deleteKey(clientWatcherKey); - redisDataStore.deleteKey(watcherField); - redisDataStore.deleteKey(fieldWatcher); + cacheDataStore.deleteKey(key); + cacheDataStore.deleteKey(clientWatcherKey); + cacheDataStore.deleteKey(watcherField); + cacheDataStore.deleteKey(fieldWatcher); } } - String objectWatchedFieldKey = RedisKeyUtils.objectWatchedFields(classIdPair.getClassName(), classIdPair.getID()); - Set objectWatcherValueKeys = redisDataStore.getHashKeys(objectWatchedFieldKey); + String objectWatchedFieldKey = RedisKeyUtils.objectWatchedFields(category, subCategory); + Set objectWatcherValueKeys = cacheDataStore.getHashKeys(objectWatchedFieldKey); Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); while (itrObjectWatcherValueKeys.hasNext()) { String nextObjectWatcherValueKey = (String) itrObjectWatcherValueKeys.next(); // Get all fields for this object that are being watched and remove them. - String changeWatcherKey = (String) redisDataStore.getHashValue(objectWatchedFieldKey, nextObjectWatcherValueKey); - redisDataStore.deleteKey(changeWatcherKey); + String changeWatcherKey = (String) cacheDataStore.getHashValue(objectWatchedFieldKey, nextObjectWatcherValueKey); + cacheDataStore.deleteKey(changeWatcherKey); } - redisDataStore.deleteKey(objectWatchedFieldKey); // Removes ALL change watcher values for this Object. + cacheDataStore.deleteKey(objectWatchedFieldKey); // Removes ALL change watcher values for this Object. - redisDataStore.deleteKey(classKey); // Removes ALL change watcher values for this Object. + cacheDataStore.deleteKey(categoryKey); // Removes ALL change watcher values for this Object. } public void saveChangeWatcherResult(ClassIDPair classIdPair, String fieldName, Object result) { @@ -1176,7 +1192,7 @@ public void saveChangeWatcherResult(ClassIDPair classIdPair, String fieldName, O HashMap resultHash = new HashMap(); resultHash.put(RedisKeyUtils.changeWatcherValueTimestamp(fieldName, params), System.currentTimeMillis()); resultHash.put(RedisKeyUtils.changeWatcherValueResult(fieldName, params), result); - redisDataStore.setAllHashValues(classKey, resultHash); + cacheDataStore.setAllHashValues(classKey, resultHash); } public void removeChangeWatcherResult(ClassIDPair classIdPair, String fieldName) { @@ -1187,8 +1203,8 @@ public void removeChangeWatcherResult(ClassIDPair classIdPair, String fieldName) public void removeChangeWatcherResult(ClassIDPair classIdPair, String fieldName, String[] params) { String key = RedisKeyUtils.changeWatcherClass(classIdPair.getClassName(), classIdPair.getID()); - redisDataStore.deleteHashKey(key, RedisKeyUtils.changeWatcherValueTimestamp(fieldName, params)); - redisDataStore.deleteHashKey(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); + cacheDataStore.deleteHashKey(key, RedisKeyUtils.changeWatcherValueTimestamp(fieldName, params)); + cacheDataStore.deleteHashKey(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); } public Long getChangeWatcherResultTimestamp(ClassIDPair classIdPair, String fieldName) { @@ -1198,7 +1214,7 @@ public Long getChangeWatcherResultTimestamp(ClassIDPair classIdPair, String fiel public Long getChangeWatcherResultTimestamp(ClassIDPair classIdPair, String fieldName, String[] params) { String key = RedisKeyUtils.changeWatcherClass(classIdPair.getClassName(), classIdPair.getID()); - Long result = (Long) redisDataStore.getHashValue(key, RedisKeyUtils.changeWatcherValueTimestamp(fieldName, params)); + Long result = (Long) cacheDataStore.getHashValue(key, RedisKeyUtils.changeWatcherValueTimestamp(fieldName, params)); return result; } @@ -1253,7 +1269,7 @@ public Boolean getChangeWatcherResultExists(ClassIDPair classIdPair, String fiel public Boolean getChangeWatcherResultExists(ClassIDPair classIdPair, String fieldName, String[] params) { String key = RedisKeyUtils.changeWatcherClass(classIdPair.getClassName(), classIdPair.getID()); - Boolean hasKey = redisDataStore.hasHashKey(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); + Boolean hasKey = cacheDataStore.hasHashKey(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); return hasKey; } @@ -1265,7 +1281,7 @@ public Object getChangeWatcherResult(ClassIDPair classIdPair, String fieldName) public Object getChangeWatcherResult(ClassIDPair classIdPair, String fieldName, String[] params) { String key = RedisKeyUtils.changeWatcherClass(classIdPair.getClassName(), classIdPair.getID()); - return redisDataStore.getHashValue(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); + return cacheDataStore.getHashValue(key, RedisKeyUtils.changeWatcherValueResult(fieldName, params)); } public void checkChangeWatchers(ClassIDPair classIdPair) { @@ -1306,18 +1322,42 @@ protected Collection getChangeWatchersForField(ClassIDPair classIdPair, } else { String fieldWatcherKey = ""; - if (params != null) + // Also add for ALL objects of this class type + String allClassObjectsFieldWatcherKey = ""; + if (params != null) { fieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), classIdPair.getID(), fieldName, params)); - else + allClassObjectsFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), "0", fieldName, params)); + } + else { fieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), fieldName)); + allClassObjectsFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), "0", fieldName)); + } + fieldWatcherKeys.add(fieldWatcherKey); + fieldWatcherKeys.add(allClassObjectsFieldWatcherKey); } } } + // Also add for this object of this class type with NO field name + String noFieldWatcherKey = ""; + // Also add for ALL objects of this class type with NO field name + String allClassObjectsNoFieldWatcherKey = ""; + if (params != null) { + noFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), classIdPair.getID(), "", params)); + allClassObjectsNoFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcherWithParams(classIdPair.getClassName(), "0", "", params)); + } + else { + noFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), classIdPair.getID(), "")); + allClassObjectsNoFieldWatcherKey = RedisKeyUtils.fieldWatcher(RedisKeyUtils.changeWatcher(classIdPair.getClassName(), "0", "")); + } + + fieldWatcherKeys.add(noFieldWatcherKey); + fieldWatcherKeys.add(allClassObjectsNoFieldWatcherKey); + Collection changeWatchers = null; if (fieldWatcherKeys.size() > 0) { - changeWatchers = (Set) redisDataStore.getSetUnion(null, fieldWatcherKeys); + changeWatchers = (Set) cacheDataStore.getSetUnion(null, fieldWatcherKeys); } return changeWatchers; @@ -1327,14 +1367,22 @@ protected Set getAllFieldWatchersForObject(ClassIDPair classIdPair) { Set fieldWatcherKeys = new HashSet(); String objectWatchedFieldKey = RedisKeyUtils.objectWatchedFields(classIdPair.getClassName(), classIdPair.getID()); - Set objectWatcherValueKeys = redisDataStore.getHashKeys(objectWatchedFieldKey); - Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); - while (itrObjectWatcherValueKeys.hasNext()) { - String nextObjectWatcherValueKey = (String) itrObjectWatcherValueKeys.next(); + // Also add for ALL objects of this class type + String allObjectsWatchedFieldKey = RedisKeyUtils.objectWatchedFields(classIdPair.getClassName(), "0"); - // Get all fields for this object that are being watched and remove them. - String changeWatcherKey = (String) redisDataStore.getHashValue(objectWatchedFieldKey, nextObjectWatcherValueKey); - fieldWatcherKeys.add(changeWatcherKey); + String[] fieldKeys = {objectWatchedFieldKey, allObjectsWatchedFieldKey}; + + for(int i=0; i objectWatcherValueKeys = cacheDataStore.getHashKeys(nextKey); + Iterator itrObjectWatcherValueKeys = objectWatcherValueKeys.iterator(); + while (itrObjectWatcherValueKeys.hasNext()) { + String nextObjectWatcherValueKey = (String) itrObjectWatcherValueKeys.next(); + + // Get all fields for this object that are being watched and remove them. + String changeWatcherKey = (String) cacheDataStore.getHashValue(nextKey, nextObjectWatcherValueKey); + fieldWatcherKeys.add(changeWatcherKey); + } } return fieldWatcherKeys; @@ -1367,7 +1415,7 @@ protected Long removeChangeWatcherForField(ClassIDPair classIdPair, String[] fie Iterator itrFieldWatcherKeys = fieldWatcherKeys.iterator(); while (itrFieldWatcherKeys.hasNext()) { String nextFieldWatcherKey = itrFieldWatcherKeys.next(); - Long countRemoved = redisDataStore.removeSetValue(nextFieldWatcherKey, changeWatcherId); + Long countRemoved = cacheDataStore.removeSetValue(nextFieldWatcherKey, changeWatcherId); result += countRemoved; } } @@ -1399,11 +1447,11 @@ public void recalculateChangeWatcher(String changeWatcherId) { // Need to break up String[] params = changeWatcherId.split(":"); - // 3rd var should be class name. - String className = params[2]; + // 3rd var should be category. + String category = params[2]; - // 4th var should be classId. - String classId = params[3]; + // 4th var should be subCategory. + String subCategory = params[3]; // 5th var should be fieldName. String fieldName = params[4]; @@ -1418,11 +1466,11 @@ public void recalculateChangeWatcher(String changeWatcherId) { if (changeWatcherHelperFactory != null) { - Collection clientIds = (Set) redisDataStore.getSetValue(RedisKeyUtils.clientWatcher(changeWatcherId)); // The list of ClientID's who are interested in this object. - ClassIDPair pair = new ClassIDPair(classId, className); + Collection clientIds = (Set) cacheDataStore.getSetValue(RedisKeyUtils.clientWatcher(changeWatcherId)); // The list of ClientID's who are interested in this object. + + IChangeWatcherHelper cwh = changeWatcherHelperFactory.getHelper(category); + cwh.reprocess(category, subCategory, fieldName, clientIds, otherParams, requestTimestamp); - IChangeWatcherHelper cwh = changeWatcherHelperFactory.getHelper(className); - cwh.recalculate(fieldName, pair, clientIds, otherParams, requestTimestamp); /** // If no clients interested in this value, then remove it from the cache. if (clientIds == null || clientIds.isEmpty()) { diff --git a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java index 249e9cf..75d8704 100644 --- a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java +++ b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelper.java @@ -1,48 +1,34 @@ package com.percero.agents.sync.cw; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import org.apache.log4j.Logger; -import org.codehaus.jackson.map.ObjectMapper; -import org.joda.time.DateTime; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; import com.mchange.v2.lang.ObjectUtils; import com.percero.agents.sync.access.IAccessManager; -import com.percero.agents.sync.hibernate.SyncHibernateUtils; -import com.percero.agents.sync.metadata.IMappedClassManager; -import com.percero.agents.sync.metadata.MappedClass; -import com.percero.agents.sync.metadata.MappedClassManagerFactory; -import com.percero.agents.sync.services.IDataProvider; -import com.percero.agents.sync.services.IDataProviderManager; -import com.percero.agents.sync.services.IPushSyncHelper; -import com.percero.agents.sync.services.ISyncAgentService; import com.percero.agents.sync.vo.BaseDataObject; import com.percero.agents.sync.vo.ClassIDPair; -import com.percero.agents.sync.vo.IClassIDPair; -import com.percero.agents.sync.vo.PushCWUpdateResponse; import com.percero.framework.vo.IPerceroObject; +/** + * ChangeWatcherHelper allows code to be executed upon the change of any model + * data. The ChangeWatcherHelper is used as the mechanism to execute that code. + * A ChangeWatcherHelper must be registered with the ChangeWatcherHelperFactory. + * Ex: ChangeWatcherHelperFactory.getInstance().registerChangeWatcherHelper( + * "category", this ); + * + * @author Collin Brown + * + */ @Component public class ChangeWatcherHelper implements IChangeWatcherHelper { private static final Logger log = Logger.getLogger(ChangeWatcherHelper.class); - @Autowired - ObjectMapper objectMapper; - -// @Scheduled(fixedRate=10000) -// public void printStats() { -// log.debug(ChangeWatcherReporting.stringResults()); -// } @Autowired protected IAccessManager accessManager; @@ -50,386 +36,29 @@ public void setAccessManager(IAccessManager value) { accessManager = value; } - @Autowired - protected IDataProviderManager dataProviderManager; - public void setDataProviderManager(IDataProviderManager value) { - dataProviderManager = value; - } - public IDataProviderManager getDataProviderManager() { - return dataProviderManager; - } - - @Autowired - protected ISyncAgentService syncAgentService; - public void setSyncAgentService(ISyncAgentService value) { - syncAgentService = value; - } - public ISyncAgentService getSyncAgentService() { - return syncAgentService; - } - - @Autowired - protected IPushSyncHelper pushSyncHelper; - public void setPushSyncHelper(IPushSyncHelper value) { - pushSyncHelper = value; - } - - - public Object get(String fieldName, ClassIDPair classIdPair) { - return get(fieldName, classIdPair, null, null); - } - - public Object get(String fieldName, ClassIDPair classIdPair, String clientId) { - return get(fieldName, classIdPair, null, clientId); - } - - - public Object get(String fieldName, ClassIDPair classIdPair, String[] params) { - return get(fieldName, classIdPair, params, null); - } - - public Object get(String fieldName, ClassIDPair classIdPair, String[] params, String clientId) { - Object result = null; - try { - // Make sure this being requested by a valid person. - if (StringUtils.hasText(clientId)) { - String userId = accessManager.getClientUserId(clientId); - if (!StringUtils.hasLength(userId)) { - log.warn("Invalid clientId in get: " + fieldName); - return result; - } - } - - // Check to see if this value has already been calculated. - Boolean resultExists = accessManager.getChangeWatcherResultExists(classIdPair, fieldName, params); - - if (resultExists) { -// Long resultTimestamp = accessManager.getChangeWatcherResultTimestamp(classIdPair, fieldName, params); - result = accessManager.getChangeWatcherResult(classIdPair, fieldName, params); - } - else { - // Result has not been calculated, so need to calculate. - result = calculate(fieldName, classIdPair, params); - } - - if (StringUtils.hasText(clientId)) { - result = getForClient(fieldName, classIdPair, params, result, clientId); - accessManager.addWatcherClient(classIdPair, fieldName, clientId, params); - } - } catch(Exception e) { - log.error("Unable to get " + fieldName, e); - } - - return result; - } - - @SuppressWarnings("rawtypes") - protected Object getForClient(String fieldName, ClassIDPair classIdPair, String[] params, Object result, String clientId) { - - String userId = accessManager.getClientUserId(clientId); - - if (result instanceof IPerceroObject) { - if (validateReadAccess((BaseDataObject) result, userId)) - return result; - else - return null; - } - if (result instanceof IClassIDPair) { - if (validateReadAccess((ClassIDPair) result, userId)) - return result; - else - return null; - } - else if (result instanceof Collection) { - Iterator itr = ((Collection) result).iterator(); - while(itr.hasNext()) { - Object next = itr.next(); - - if (next instanceof IPerceroObject) { - if (!validateReadAccess((BaseDataObject) next, userId)) { - itr.remove(); - } - } - else if (next instanceof IClassIDPair) { - if (!validateReadAccess((ClassIDPair) next, userId)) { - itr.remove(); - } - } - } - - return result; - } - else { - return result; - } - } - - protected Boolean validateReadAccess(BaseDataObject bdo, String userId) { - return validateReadAccess(new ClassIDPair(bdo.getID(), bdo.getClass().getCanonicalName()), userId); - } - - protected Boolean validateReadAccess(ClassIDPair classIdPair, String userId) { - String className = classIdPair.getClassName(); - String id = classIdPair.getID(); - IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); - MappedClass mappedClass = mcm.getMappedClassByClassName(className); - Boolean hasAccess = true; - - if (mappedClass != null) { - IDataProviderManager dataProviderManager = getDataProviderManager(); - - IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); - hasAccess = dataProvider.getReadAccess(new ClassIDPair(id, className), userId); - } - - if (hasAccess) - return true; - else - return false; - } - - public Object calculate(String fieldName, ClassIDPair classIdPair) { - return null; + public void process(String category, String subCategory, String fieldName) { + // This is really an error. + StringBuilder strBuilder = new StringBuilder("No value calculate method found for: ").append(category).append(":").append(subCategory).append(":").append(fieldName); + log.error(strBuilder.toString()); } - public Object calculate(String fieldName, ClassIDPair classIdPair, String[] params) { + public void process(String category, String subCategory, String fieldName, String[] params) { // This is really an error. - StringBuilder strBuilder = new StringBuilder("No value calculate method found for: ").append(classIdPair.getClassName()).append(":").append(fieldName); + StringBuilder strBuilder = new StringBuilder("No value process method found for: ").append(category).append(":").append(subCategory).append(":").append(fieldName); for(String nextString : params) { strBuilder.append(".").append(nextString); } log.error(strBuilder.toString()); - return null; - } - - /**protected void postCalculate(String fieldName, ClassIDPair classIdPair, Object result, Object oldValue) { - postCalculate(fieldName, classIdPair, result, null); - }*/ - private Map changeWatcherResults = new HashMap(); - protected void postCalculate(String fieldName, ClassIDPair classIdPair, String[] params, Object result, Object oldValue) { - // Now run past the ChangeWatcher. - try { - String cwResultKey = fieldName + classIdPair.toString() + (params == null ? "" : params.toString()); - ChangeWatcherResult cwResult = changeWatcherResults.get(cwResultKey); - if (cwResult == null) { - cwResult = new ChangeWatcherResult(oldValue, result, eqOrBothNull(oldValue, result)); - } - else { - cwResult.setNewValue(result); - cwResult.setEqOrBothNull(eqOrBothNull(oldValue, result)); - } - - // Check to see if this value has already been calculated. - if (cwResult.getEqOrBothNull()) { - ChangeWatcherReporting.unchangedResultsCounter++; -// log.debug("Object has not changed, so not checking ChangeWatchers."); - } - else { - ChangeWatcherReporting.changedResultsCounter++; - String[] fieldNames = null; - if (StringUtils.hasText(fieldName)) { - fieldNames = new String[1]; - fieldNames[0] = fieldName; - } - accessManager.checkChangeWatchers(classIdPair, fieldNames, params); - } - } catch (Exception e) { - log.error("Unable to chech change watchers for " + classIdPair.getID() + " / " + fieldName + " in " + getClass().getCanonicalName()); - } } - public void recalculate(String fieldName, ClassIDPair classIdPair, Collection clientIds, String[] params, Long requestTimestamp) { - Object value = null; - - // Check to see if this value has already been calculated. - Object currentValue = null; - ChangeWatcherReporting.recalcsCounter++; - try { - if (requestTimestamp != null) { - Long resultTimestamp = accessManager.getChangeWatcherResultTimestamp(classIdPair, fieldName, params); - if (resultTimestamp != null && resultTimestamp.compareTo(requestTimestamp) > 0) { - // If the result timestamp is after the request timestamp, then no need to recalculate. - // In essence, the recalc was already done, albeit at the behest of another process. - ChangeWatcherReporting.abortedRecalcsCounter++; -// log.debug("Aborting ChangeWatcherHelper.recalculate request since it has already been fulfilled."); - return; - } - } - currentValue = accessManager.getChangeWatcherResult(classIdPair, fieldName, params); - } catch(Exception e) {} - - - String cwResultKey = fieldName + classIdPair.toString() + (params == null ? "" : params.toString()); - ChangeWatcherResult cwResult = new ChangeWatcherResult(currentValue); - changeWatcherResults.put(cwResultKey, cwResult); - - // TODO: Pass the ChangeWatcherResult to calculate so that we don't have to retrieve the current value twice. - value = calculate(fieldName, classIdPair, params); - changeWatcherResults.remove(cwResultKey); - - if (!cwResult.getEqOrBothNull()) { -// ChangeWatcherReporting.unchangedResultsCounter++; - log.debug("Object has changed, pushing update."); - pushUpdate(classIdPair, fieldName, params, value, clientIds); - } + public void reprocess(String category, String subCategory, String fieldName, Collection clientIds, String[] params, Long requestTimestamp) { + ChangeWatcherReporting.reprocessCounter++; + process(category, subCategory, fieldName, params); log.debug(ChangeWatcherReporting.stringResults()); } - - protected void pushUpdate(ClassIDPair classIdPair, String fieldName, String[] params, Object update, Collection clientIds) { - // Now push the result to all interested clients. - try { - Iterator itrClientIds = clientIds.iterator(); - while(itrClientIds.hasNext()) { - String nextClient = itrClientIds.next(); - Object nextUpdate = getForClient(fieldName, classIdPair, params, update, nextClient); - pushChangeWatcherUpdate(nextClient, classIdPair, fieldName, params, nextUpdate); - } - } catch(Exception e) { - log.error("Unable to pushUpdate", e); - } - } - - - public void pushChangeWatcherUpdate(Collection clientIds, ClassIDPair classIdPair, String fieldName, String[] params, Object value) { - if (clientIds != null && clientIds.size() > 0) { - try { - PushCWUpdateResponse pushUpdateResponse = new PushCWUpdateResponse(); - pushUpdateResponse.setFieldName(fieldName); - pushUpdateResponse.setParams(params); - pushUpdateResponse.setClassIdPair(classIdPair); - - for(Object nextClient : clientIds) { - - String clientId = (String) nextClient; - if (!StringUtils.hasLength(clientId)) - continue; - - //if (value instanceof BaseDataObject) { - String userId = accessManager.getClientUserId(clientId); - // Clean the value if it is a framework object. - value = SyncHibernateUtils.cleanObject(value, null, userId); - //} - pushUpdateResponse.setValue(value); - pushUpdateResponse.setClientId(clientId); - - pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, clientId); - } - - } catch(Exception e) { - log.error("Error sending ChangeWatcher Updates to clients", e); - } - } - } - public void pushChangeWatcherUpdate(String clientId, ClassIDPair classIdPair, String fieldName, String[] params, Object value) { - if (StringUtils.hasText(clientId)) { - try { - PushCWUpdateResponse pushUpdateResponse = new PushCWUpdateResponse(); - pushUpdateResponse.setFieldName(fieldName); - pushUpdateResponse.setParams(params); - pushUpdateResponse.setClassIdPair(classIdPair); - - if (value instanceof IPerceroObject) { - String userId = accessManager.getClientUserId(clientId); - // Clean the value if it is a framework object. - value = (BaseDataObject) SyncHibernateUtils.cleanObject(value, null, userId); - } - pushUpdateResponse.setValue(value); - - pushUpdateResponse.setClientId(clientId); - - pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, clientId); - - } catch(Exception e) { - log.error("Error sending ChangeWatcher Updates to clients", e); - } - } - } - - /**************************** - * HELPER FUNCTIONS - ****************************/ - public DateTime parseDateTime(String theDate) { - String testDate = theDate.replace('_', ' '); - DateTime dateTime = null; - if (dateTime == null) { - try { - dateTime = new DateTime(Long.parseLong(theDate)); - } catch(IllegalArgumentException e) { - // Possibly the wrong format date, try a different format. - } - } - - //testDate = "2013-10-01 +07:00"; - DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ZZ"); - if (dateTime == null) { - try { - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss Z"); - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ZZZ"); - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); - dateTime = formatter.parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd ZZZ"); - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd ZZ"); - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd Z"); - dateTime = formatter.withOffsetParsed().parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - if (dateTime == null) { - try { - formatter = DateTimeFormat.forPattern("yyyy-MM-dd"); - dateTime = formatter.parseDateTime(testDate); - } catch(IllegalArgumentException iae) { - // Possibly the wrong format date, try a different format. - } - } - - return dateTime; - } @SuppressWarnings("unchecked") public static boolean eqOrBothNull(Object resultA, Object resultB) { diff --git a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelperFactory.java b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelperFactory.java index cbe6c2e..8783440 100644 --- a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelperFactory.java +++ b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherHelperFactory.java @@ -34,16 +34,23 @@ public static IChangeWatcherHelperFactory getInstance() { public ChangeWatcherHelperFactory() { currentInstance = this; } + + public void registerChangeWatcherHelper(String category, IChangeWatcherHelper changeWatcherHelper) { + IChangeWatcherHelper existingHelper = helperCache.get(category); + if (existingHelper == null) { + helperCache.put(category, changeWatcherHelper); + } + } private Map helperCache = new HashMap(); @SuppressWarnings({ "rawtypes", "unchecked" }) - public IChangeWatcherHelper getHelper(String className) { - IChangeWatcherHelper helper = helperCache.get(className); + public IChangeWatcherHelper getHelper(String category) { + IChangeWatcherHelper helper = helperCache.get(category); if (helper == null) { // Get the appropriate Helper Component. try { - Class clazz = MappedClass.forName(className); + Class clazz = MappedClass.forName(category); while (clazz != null) { try { // Get the class name only. @@ -55,7 +62,7 @@ public IChangeWatcherHelper getHelper(String className) { //String helperClassName = (new StringBuilder(className).append("CWHelper")).toString(); helper = (IChangeWatcherHelper) context.getBean(StringUtils.uncapitalize(theClassName) + "CWHelper", MappedClass.forName(helperClassName)); if (helper != null) { - helperCache.put(className, helper); + helperCache.put(category, helper); return helper; } } catch(Exception e) { @@ -65,7 +72,7 @@ public IChangeWatcherHelper getHelper(String className) { clazz = clazz.getSuperclass(); } } catch(Exception e) { - log.error("Unable to get ChangeWatcherHelper for " + className, e); + log.error("Unable to get ChangeWatcherHelper for " + category, e); } return null; diff --git a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherReporting.java b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherReporting.java index a460b89..09e3bd0 100644 --- a/src/main/java/com/percero/agents/sync/cw/ChangeWatcherReporting.java +++ b/src/main/java/com/percero/agents/sync/cw/ChangeWatcherReporting.java @@ -7,6 +7,7 @@ public class ChangeWatcherReporting { public static Integer recalcsCounter = 0; public static Integer abortedRecalcsCounter = 0; + public static Integer reprocessCounter = 0; public static Integer unchangedResultsCounter = 0; public static Integer changedResultsCounter = 0; @@ -17,6 +18,7 @@ public static String stringResults() { result.append("Internal Requests: ").append(internalRequestsCounter).append("\n"); result.append("Unchanged Results: ").append(unchangedResultsCounter).append("\n"); result.append("Changed Results: ").append(changedResultsCounter).append("\n"); + result.append("Reprocess: ").append(reprocessCounter).append("\n"); result.append("Recalcs: ").append(recalcsCounter).append("\n"); result.append("Aborted Recalcs: ").append(abortedRecalcsCounter).append("\n"); result.append("Aborted %: ").append((100.0 * abortedRecalcsCounter / recalcsCounter)).append("\n"); diff --git a/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java b/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java new file mode 100644 index 0000000..8f28c61 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/cw/DerivedValueChangeWatcherHelper.java @@ -0,0 +1,459 @@ +package com.percero.agents.sync.cw; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import com.percero.agents.sync.hibernate.SyncHibernateUtils; +import com.percero.agents.sync.metadata.IMappedClassManager; +import com.percero.agents.sync.metadata.MappedClass; +import com.percero.agents.sync.metadata.MappedClassManagerFactory; +import com.percero.agents.sync.services.IDataProvider; +import com.percero.agents.sync.services.IDataProviderManager; +import com.percero.agents.sync.services.IPushSyncHelper; +import com.percero.agents.sync.services.ISyncAgentService; +import com.percero.agents.sync.vo.BaseDataObject; +import com.percero.agents.sync.vo.ClassIDPair; +import com.percero.agents.sync.vo.IClassIDPair; +import com.percero.agents.sync.vo.PushCWUpdateResponse; +import com.percero.framework.vo.IPerceroObject; + +/** + * Customized Change Watcher for calculating Derived Values. Derived Values are + * properties on the data model that are derived from other properties and thus + * NOT stored in the data store. Derived Values are stored in the cache, along + * with the triggers necessary to recalculate them. + * + * For each Derived Value, a Change Watcher is meant to be set on each and every + * property that could potentially effect the resultant Derived Value. When one + * of those values changes, the Change Watcher will cause the Derived Value to + * be recalculated. Changes to a Derived Value are also automatically pushed out + * to all Clients who have registered interest in that Derived Value. + * + * Dynamic parameters can be used to register for a Derived Value. For example, + * a daily report roll-up could use the Date as part of the name of the Derived + * Value. These parameters are passed as part of the name (ie. identifier) of + * the Derived Value. + * + * @author Collin Brown + * + */ +@Component +public class DerivedValueChangeWatcherHelper extends ChangeWatcherHelper implements IChangeWatcherValueHelper { + + private static final Logger log = Logger.getLogger(ChangeWatcherHelper.class); + + @Autowired + protected IPushSyncHelper pushSyncHelper; + public void setPushSyncHelper(IPushSyncHelper value) { + pushSyncHelper = value; + } + + @Autowired + protected IDataProviderManager dataProviderManager; + public void setDataProviderManager(IDataProviderManager value) { + dataProviderManager = value; + } + public IDataProviderManager getDataProviderManager() { + return dataProviderManager; + } + + @Autowired + protected ISyncAgentService syncAgentService; + public void setSyncAgentService(ISyncAgentService value) { + syncAgentService = value; + } + public ISyncAgentService getSyncAgentService() { + return syncAgentService; + } + + + public Object calculate(String fieldName, ClassIDPair classIdPair) { + // This is really an error. + StringBuilder strBuilder = new StringBuilder("No value calculate method found for: ").append(classIdPair.getClassName()).append(":").append(fieldName); + log.error(strBuilder.toString()); + return null; + } + + public Object calculate(String fieldName, ClassIDPair classIdPair, String[] params) { + // This is really an error. + StringBuilder strBuilder = new StringBuilder("No value calculate method found for: ").append(classIdPair.getClassName()).append(":").append(fieldName); + for(String nextString : params) { + strBuilder.append(".").append(nextString); + } + log.error(strBuilder.toString()); + return null; + } + + @Override + public void process(String category, String subCategory, String fieldName) { + calculate(fieldName, new ClassIDPair(subCategory, category)); + } + + @Override + public void process(String category, String subCategory, String fieldName, String[] params) { + calculate(fieldName, new ClassIDPair(subCategory, category), params); + } + + /**protected void postCalculate(String fieldName, ClassIDPair classIdPair, Object result, Object oldValue) { + postCalculate(fieldName, classIdPair, result, null); + }*/ + private Map changeWatcherResults = new HashMap(); + protected void postCalculate(String fieldName, ClassIDPair classIdPair, String[] params, Object result, Object oldValue) { + // Now run past the ChangeWatcher. + try { + String cwResultKey = fieldName + classIdPair.toString() + (params == null ? "" : params.toString()); + ChangeWatcherResult cwResult = changeWatcherResults.get(cwResultKey); + if (cwResult == null) { + cwResult = new ChangeWatcherResult(oldValue, result, eqOrBothNull(oldValue, result)); + } + else { + cwResult.setNewValue(result); + cwResult.setEqOrBothNull(eqOrBothNull(oldValue, result)); + } + + // Check to see if this value has already been calculated. + if (cwResult.getEqOrBothNull()) { + ChangeWatcherReporting.unchangedResultsCounter++; +// log.debug("Object has not changed, so not checking ChangeWatchers."); + } + else { + ChangeWatcherReporting.changedResultsCounter++; + String[] fieldNames = null; + if (StringUtils.hasText(fieldName)) { + fieldNames = new String[1]; + fieldNames[0] = fieldName; + } + accessManager.checkChangeWatchers(classIdPair, fieldNames, params); + } + } catch (Exception e) { + log.error("Unable to chech change watchers for " + classIdPair.getID() + " / " + fieldName + " in " + getClass().getCanonicalName()); + } + } + + + public void recalculate(String fieldName, ClassIDPair classIdPair, Collection clientIds, String[] params, Long requestTimestamp) { + Object value = null; + + // Check to see if this value has already been calculated. + Object currentValue = null; + ChangeWatcherReporting.recalcsCounter++; + try { + if (requestTimestamp != null) { + Long resultTimestamp = accessManager.getChangeWatcherResultTimestamp(classIdPair, fieldName, params); + if (resultTimestamp != null && resultTimestamp.compareTo(requestTimestamp) > 0) { + // If the result timestamp is after the request timestamp, then no need to recalculate. + // In essence, the recalc was already done, albeit at the behest of another process. + ChangeWatcherReporting.abortedRecalcsCounter++; +// log.debug("Aborting ChangeWatcherHelper.recalculate request since it has already been fulfilled."); + return; + } + } + currentValue = accessManager.getChangeWatcherResult(classIdPair, fieldName, params); + } catch(Exception e) {} + + + String cwResultKey = fieldName + classIdPair.toString() + (params == null ? "" : params.toString()); + ChangeWatcherResult cwResult = new ChangeWatcherResult(currentValue); + changeWatcherResults.put(cwResultKey, cwResult); + + // TODO: Pass the ChangeWatcherResult to calculate so that we don't have to retrieve the current value twice. + value = calculate(fieldName, classIdPair, params); + changeWatcherResults.remove(cwResultKey); + + if (!cwResult.getEqOrBothNull()) { +// ChangeWatcherReporting.unchangedResultsCounter++; + log.debug("Object has changed, pushing update."); + pushUpdate(classIdPair, fieldName, params, value, clientIds); + } + + log.debug(ChangeWatcherReporting.stringResults()); + } + + @Override + public void reprocess(String category, String subCategory, String fieldName, Collection clientIds, String[] params, Long requestTimestamp) { + ChangeWatcherReporting.reprocessCounter++; + this.recalculate(fieldName, new ClassIDPair(subCategory, category), clientIds, params, requestTimestamp); + } + + + + public Object get(String fieldName, ClassIDPair classIdPair) { + return get(fieldName, classIdPair, null, null); + } + + public Object get(String fieldName, ClassIDPair classIdPair, String clientId) { + return get(fieldName, classIdPair, null, clientId); + } + + + public Object get(String fieldName, ClassIDPair classIdPair, String[] params) { + return get(fieldName, classIdPair, params, null); + } + + public Object get(String fieldName, ClassIDPair classIdPair, String[] params, String clientId) { + Object result = null; + try { + // Make sure this being requested by a valid person. + if (StringUtils.hasText(clientId)) { + String userId = accessManager.getClientUserId(clientId); + if (!StringUtils.hasLength(userId)) { + log.warn("Invalid clientId in get: " + fieldName); + return result; + } + } + + // Check to see if this value has already been calculated. + Boolean resultExists = accessManager.getChangeWatcherResultExists(classIdPair, fieldName, params); + + if (resultExists) { +// Long resultTimestamp = accessManager.getChangeWatcherResultTimestamp(classIdPair, fieldName, params); + result = accessManager.getChangeWatcherResult(classIdPair, fieldName, params); + } + else { + // Result has not been calculated, so need to calculate. + result = calculate(fieldName, classIdPair, params); + } + + if (StringUtils.hasText(clientId)) { + result = getForClient(fieldName, classIdPair, params, result, clientId); + accessManager.addWatcherClient(classIdPair, fieldName, clientId, params); + } + } catch(Exception e) { + log.error("Unable to get " + fieldName, e); + } + + return result; + } + + @SuppressWarnings("rawtypes") + protected Object getForClient(String fieldName, ClassIDPair classIdPair, String[] params, Object result, String clientId) { + + String userId = accessManager.getClientUserId(clientId); + + if (result instanceof IPerceroObject) { + if (validateReadAccess((BaseDataObject) result, userId)) + return result; + else + return null; + } + if (result instanceof IClassIDPair) { + if (validateReadAccess((ClassIDPair) result, userId)) + return result; + else + return null; + } + else if (result instanceof Collection) { + Iterator itr = ((Collection) result).iterator(); + while(itr.hasNext()) { + Object next = itr.next(); + + if (next instanceof IPerceroObject) { + if (!validateReadAccess((BaseDataObject) next, userId)) { + itr.remove(); + } + } + else if (next instanceof IClassIDPair) { + if (!validateReadAccess((ClassIDPair) next, userId)) { + itr.remove(); + } + } + } + + return result; + } + else { + return result; + } + } + + protected Boolean validateReadAccess(BaseDataObject bdo, String userId) { + return validateReadAccess(new ClassIDPair(bdo.getID(), bdo.getClass().getCanonicalName()), userId); + } + + protected Boolean validateReadAccess(ClassIDPair classIdPair, String userId) { + String className = classIdPair.getClassName(); + String id = classIdPair.getID(); + IMappedClassManager mcm = MappedClassManagerFactory.getMappedClassManager(); + MappedClass mappedClass = mcm.getMappedClassByClassName(className); + Boolean hasAccess = true; + + if (mappedClass != null) { + IDataProviderManager dataProviderManager = getDataProviderManager(); + + IDataProvider dataProvider = dataProviderManager.getDataProviderByName(mappedClass.dataProviderName); + hasAccess = dataProvider.getReadAccess(new ClassIDPair(id, className), userId); + } + + if (hasAccess) + return true; + else + return false; + } + + + + protected void pushUpdate(ClassIDPair classIdPair, String fieldName, String[] params, Object update, Collection clientIds) { + // Now push the result to all interested clients. + try { + Iterator itrClientIds = clientIds.iterator(); + while(itrClientIds.hasNext()) { + String nextClient = itrClientIds.next(); + Object nextUpdate = getForClient(fieldName, classIdPair, params, update, nextClient); + pushChangeWatcherUpdate(nextClient, classIdPair, fieldName, params, nextUpdate); + } + } catch(Exception e) { + log.error("Unable to pushUpdate", e); + } + } + + + public void pushChangeWatcherUpdate(Collection clientIds, ClassIDPair classIdPair, String fieldName, String[] params, Object value) { + if (clientIds != null && clientIds.size() > 0) { + try { + PushCWUpdateResponse pushUpdateResponse = new PushCWUpdateResponse(); + pushUpdateResponse.setFieldName(fieldName); + pushUpdateResponse.setParams(params); + pushUpdateResponse.setClassIdPair(classIdPair); + + for(Object nextClient : clientIds) { + + String clientId = (String) nextClient; + if (!StringUtils.hasLength(clientId)) + continue; + + //if (value instanceof BaseDataObject) { + String userId = accessManager.getClientUserId(clientId); + // Clean the value if it is a framework object. + value = SyncHibernateUtils.cleanObject(value, null, userId); + //} + pushUpdateResponse.setValue(value); + pushUpdateResponse.setClientId(clientId); + + pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, clientId); + } + + } catch(Exception e) { + log.error("Error sending ChangeWatcher Updates to clients", e); + } + } + } + public void pushChangeWatcherUpdate(String clientId, ClassIDPair classIdPair, String fieldName, String[] params, Object value) { + if (StringUtils.hasText(clientId)) { + try { + PushCWUpdateResponse pushUpdateResponse = new PushCWUpdateResponse(); + pushUpdateResponse.setFieldName(fieldName); + pushUpdateResponse.setParams(params); + pushUpdateResponse.setClassIdPair(classIdPair); + + if (value instanceof IPerceroObject) { + String userId = accessManager.getClientUserId(clientId); + // Clean the value if it is a framework object. + value = (BaseDataObject) SyncHibernateUtils.cleanObject(value, null, userId); + } + pushUpdateResponse.setValue(value); + + pushUpdateResponse.setClientId(clientId); + + pushSyncHelper.pushSyncResponseToClient(pushUpdateResponse, clientId); + + } catch(Exception e) { + log.error("Error sending ChangeWatcher Updates to clients", e); + } + } + } + + + /**************************** + * HELPER FUNCTIONS + ****************************/ + public DateTime parseDateTime(String theDate) { + String testDate = theDate.replace('_', ' '); + DateTime dateTime = null; + if (dateTime == null) { + try { + dateTime = new DateTime(Long.parseLong(theDate)); + } catch(IllegalArgumentException e) { + // Possibly the wrong format date, try a different format. + } + } + + //testDate = "2013-10-01 +07:00"; + DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ZZ"); + if (dateTime == null) { + try { + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss Z"); + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ZZZ"); + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); + dateTime = formatter.parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd ZZZ"); + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd ZZ"); + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd Z"); + dateTime = formatter.withOffsetParsed().parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + if (dateTime == null) { + try { + formatter = DateTimeFormat.forPattern("yyyy-MM-dd"); + dateTime = formatter.parseDateTime(testDate); + } catch(IllegalArgumentException iae) { + // Possibly the wrong format date, try a different format. + } + } + + return dateTime; + } + +} diff --git a/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelper.java b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelper.java index 650d43a..9f1a02c 100644 --- a/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelper.java +++ b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelper.java @@ -2,19 +2,10 @@ import java.util.Collection; -import com.percero.agents.sync.services.IDataProviderManager; -import com.percero.agents.sync.services.ISyncAgentService; -import com.percero.agents.sync.vo.ClassIDPair; - public interface IChangeWatcherHelper { - public ISyncAgentService getSyncAgentService(); - public IDataProviderManager getDataProviderManager(); - public Object get(String fieldName, ClassIDPair classIdPair); - public Object get(String fieldName, ClassIDPair classIdPair, String clientId); - public Object get(String fieldName, ClassIDPair classIdPair, String[] params); - public Object get(String fieldName, ClassIDPair classIdPair, String[] params, String clientId); - public Object calculate(String fieldName, ClassIDPair classIdPair); - public Object calculate(String fieldName, ClassIDPair classIdPair, String[] params); - public void recalculate(String fieldName, ClassIDPair classIdPair, Collection clientIds, String[] params, Long requestTimestamp); + public void process(String category, String subCategory, String fieldName); + public void process(String category, String subCategory, String fieldName, String[] params); + public void reprocess(String category, String subCategory, String fieldName, Collection clientIds, String[] params, Long requestTimestamp); + } diff --git a/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelperFactory.java b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelperFactory.java index 7bf0e7c..0de0907 100644 --- a/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelperFactory.java +++ b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherHelperFactory.java @@ -4,4 +4,5 @@ public interface IChangeWatcherHelperFactory { public IChangeWatcherHelper getHelper(String className); + public void registerChangeWatcherHelper(String category, IChangeWatcherHelper changeWatcherHelper); } diff --git a/src/main/java/com/percero/agents/sync/cw/IChangeWatcherValueHelper.java b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherValueHelper.java new file mode 100644 index 0000000..2408de2 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/cw/IChangeWatcherValueHelper.java @@ -0,0 +1,12 @@ +package com.percero.agents.sync.cw; + +import com.percero.agents.sync.vo.ClassIDPair; + +public interface IChangeWatcherValueHelper { + + public Object get(String fieldName, ClassIDPair classIdPair); + public Object get(String fieldName, ClassIDPair classIdPair, String clientId); + public Object get(String fieldName, ClassIDPair classIdPair, String[] params); + public Object get(String fieldName, ClassIDPair classIdPair, String[] params, String clientId); + +} diff --git a/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java b/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java new file mode 100644 index 0000000..c82acf3 --- /dev/null +++ b/src/main/java/com/percero/agents/sync/datastore/ICacheDataStore.java @@ -0,0 +1,170 @@ +package com.percero.agents.sync.datastore; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.SetOperations; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.transaction.annotation.Transactional; + +public interface ICacheDataStore { + + public abstract Boolean expire(String key, long timeout, TimeUnit timeUnit); + + public abstract Boolean expire(Collection keys, long timeout, + TimeUnit timeUnit); + + public abstract Boolean expire(String key, long timeout, TimeUnit timeUnit, + Boolean forceNow); + + public abstract Boolean expire(Collection keys, long timeout, + TimeUnit timeUnit, Boolean forceNow); + + @Scheduled(fixedRate = 600000) + // 10 * 60 * 1000 -> Ten Minutes. + public abstract void postExpires(); + + public abstract Object getValue(String key); + + public abstract List getValues(Collection keys); + + public abstract void setValue(String key, Object value); + + // public void setValues( final KeyValuePair[] pairs ) { + public abstract void setValues( + Map keysAndValuesMap); + + @Transactional + public abstract Long addSetValue(String key, Object value); + + @Transactional + public abstract Long lpushListValue(String key, Object value); + + @Transactional + public abstract List listAll(String key); + + @Transactional + public abstract List listRange(String key, Long start, Long end); + + @Transactional + public abstract Object listIndex(String key, Long index); + + @Transactional + public abstract Object listIndex(String key); + + @Transactional + public abstract Object getHashValue(String key, String hashKey); + + @Transactional + public abstract Set getHashKeys(String key); + + @Transactional + public abstract Map getHashEntries(String key); + + @Transactional + public abstract Long getHashSize(String key); + + @Transactional + public abstract void deleteHashKey(String key, Object hashKey); + + @Transactional + public abstract void setHashValue(String key, String hashKey, Object value); + + @Transactional + public abstract void setAllHashValues(String key, + Map hashMap); + + @Transactional + public abstract Long removeSetValue(String key, Object value); + + @Transactional + public abstract Boolean getSetIsEmpty(String key); + + @Transactional + public abstract Long removeSetValueAndGetSize(String key, Object value); + + public abstract void removeSetsValue(Collection keys, + Object value); + + public abstract void removeSetsValue(String keysPrefix, + Collection keys, Object value); + + public abstract Boolean hasKey(String key); + + public abstract Boolean hasHashKey(String key, String hashKey); + + @Transactional + public abstract void swapHashKey(String key, String oldHashKey, + String newHashValue); + + public abstract Boolean renameIfAbsent(String oldKey, String newKey); + + public abstract void rename(String oldKey, String newKey); + + public abstract Long setUnionAndStore(String key, String otherKey, + String destKey); + + public abstract Long setUnionAndStore(String key, + Collection otherKeys, String destKey); + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#removeSetValues(java.lang.String, java.util.Collection) + */ + @Transactional + public abstract void removeSetValues(String key, + Collection values); + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetValue(java.lang.String) + */ + public abstract Set getSetValue(String key); + + @Transactional + public abstract Long replaceSet(String key, + Collection values); + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#swapSetValue(java.lang.String, java.lang.String, java.lang.String) + */ + @Transactional + public abstract void swapSetValue(String key, String oldValue, + String newValue); + + public abstract Boolean getSetIsMember(String key, Object object); + + @Transactional + public abstract Set getSetsContainsMembers( + Collection keys, Object[] membersToCheck); + + public abstract Set getSetIntersect(String key, + Collection otherKeys); + + public abstract Set getSetIntersect(String key, String otherKey); + + public abstract Set getSetUnion(String key, + Collection otherKeys); + + public abstract Set getSetUnion(String key, + String otherKey); + + public abstract void deleteKey(String key); + + public abstract void deleteKeys(Collection keys); + + @Transactional + public abstract Long setSetValue(String key, Object value); + + public abstract SetOperations getSet(String key); + + public abstract RedisTemplate getTemplate(); + + public abstract Collection keys(String pattern); + + @Transactional + public abstract void removeKeysValue(String pattern, Object value); + +} \ No newline at end of file diff --git a/src/main/java/com/percero/agents/sync/datastore/RedisDataStore.java b/src/main/java/com/percero/agents/sync/datastore/RedisCacheDataStore.java similarity index 56% rename from src/main/java/com/percero/agents/sync/datastore/RedisDataStore.java rename to src/main/java/com/percero/agents/sync/datastore/RedisCacheDataStore.java index cfbcb4d..8b28621 100644 --- a/src/main/java/com/percero/agents/sync/datastore/RedisDataStore.java +++ b/src/main/java/com/percero/agents/sync/datastore/RedisCacheDataStore.java @@ -12,32 +12,42 @@ import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.SetOperations; import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import com.percero.agents.sync.access.KeyValuePair; import com.percero.agents.sync.services.PerceroRedisTemplate; import edu.emory.mathcs.backport.java.util.Collections; -@Component -public class RedisDataStore { +public class RedisCacheDataStore implements ICacheDataStore { - private static Logger log = Logger.getLogger(RedisDataStore.class); + private static Logger log = Logger.getLogger(RedisCacheDataStore.class); @Autowired - private PerceroRedisTemplate template; + protected PerceroRedisTemplate template; + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.lang.String, long, java.util.concurrent.TimeUnit) + */ + @Override public Boolean expire( final String key, final long timeout, final TimeUnit timeUnit ) { return expire(key, timeout, timeUnit, false); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.util.Collection, long, java.util.concurrent.TimeUnit) + */ + @Override public Boolean expire( final Collection keys, final long timeout, final TimeUnit timeUnit ) { return expire(keys, timeout, timeUnit, false); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.lang.String, long, java.util.concurrent.TimeUnit, java.lang.Boolean) + */ + @Override public Boolean expire( final String key, final long timeout, final TimeUnit timeUnit, Boolean forceNow ) { if (forceNow) { return template.expire(key, timeout, timeUnit); @@ -48,6 +58,10 @@ public Boolean expire( final String key, final long timeout, final TimeUnit time } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#expire(java.util.Collection, long, java.util.concurrent.TimeUnit, java.lang.Boolean) + */ + @Override public Boolean expire( final Collection keys, final long timeout, final TimeUnit timeUnit, Boolean forceNow ) { if (forceNow) { Iterator itrKeys = keys.iterator(); @@ -71,6 +85,10 @@ public Boolean expire( final Collection keys, final long timeout, final @SuppressWarnings("unchecked") private Map expiresToBeWritten = Collections.synchronizedMap(new HashMap()); + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#postExpires() + */ + @Override @Scheduled(fixedRate=600000) // 10 * 60 * 1000 -> Ten Minutes. public void postExpires() { log.info("Posting " + expiresToBeWritten.size() + " expire" + (expiresToBeWritten.size() == 1 ? "" : "s")); @@ -112,19 +130,35 @@ public PendingExpire(String key, long timeout, TimeUnit timeUnit) { } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getValue(java.lang.String) + */ + @Override public Object getValue( final String key ) { return template.opsForValue().get( key ); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getValues(java.util.Collection) + */ + @Override public List getValues( final Collection keys ) { return template.opsForValue().multiGet(keys); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setValue(java.lang.String, java.lang.Object) + */ + @Override public void setValue( final String key, final Object value ) { template.opsForValue().set( key, value ); } // public void setValues( final KeyValuePair[] pairs ) { + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setValues(java.util.Map) + */ + @Override public void setValues( final Map keysAndValuesMap ) { template.opsForValue().multiSet(keysAndValuesMap); // if (pairs != null) { @@ -134,83 +168,146 @@ public void setValues( final Map keysAndValuesMap ) { // } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#addSetValue(java.lang.String, java.lang.Object) + */ + @Override @Transactional public Long addSetValue( final String key, final Object value ) { return template.opsForSet().add(key, value);// ? Long.valueOf(1) : Long.valueOf(0); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#lpushListValue(java.lang.String, java.lang.Object) + */ + @Override @Transactional public Long lpushListValue( final String key, final Object value ) { return template.opsForList().leftPush(key, value); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listAll(java.lang.String) + */ + @Override @Transactional public List listAll( final String key) { return listRange(key, Long.valueOf(0), Long.valueOf(-1)); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listRange(java.lang.String, java.lang.Long, java.lang.Long) + */ + @Override @Transactional public List listRange( final String key, final Long start, final Long end ) { return template.opsForList().range(key, start, end); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listIndex(java.lang.String, java.lang.Long) + */ + @Override @Transactional public Object listIndex( final String key, final Long index ) { return template.opsForList().index(key, index); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#listIndex(java.lang.String) + */ + @Override @Transactional public Object listIndex( final String key ) { return template.opsForList().index(key, Long.valueOf(0)); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashValue(java.lang.String, java.lang.String) + */ + @Override @Transactional public Object getHashValue( final String key, final String hashKey ) { return template.opsForHash().get(key, hashKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashKeys(java.lang.String) + */ + @Override @Transactional public Set getHashKeys( final String key ) { return template.opsForHash().keys(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashEntries(java.lang.String) + */ + @Override @Transactional public Map getHashEntries( final String key ) { return template.opsForHash().entries(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getHashSize(java.lang.String) + */ + @Override @Transactional public Long getHashSize( final String key ) { return template.opsForHash().size(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#deleteHashKey(java.lang.String, java.lang.Object) + */ + @Override @Transactional public void deleteHashKey( final String key, final Object hashKey ) { template.opsForHash().delete(key, hashKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setHashValue(java.lang.String, java.lang.String, java.lang.Object) + */ + @Override @Transactional public void setHashValue( final String key, final String hashKey, final Object value ) { template.opsForHash().put(key, hashKey, value); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setAllHashValues(java.lang.String, java.util.Map) + */ + @Override @Transactional public void setAllHashValues( final String key, final Map hashMap ) { template.opsForHash().putAll(key, hashMap); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetValue(java.lang.String, java.lang.Object) + */ + @Override @Transactional public Long removeSetValue( final String key, final Object value ) { - Long result = template.opsForSet().remove(key, value);// ? Long.valueOf(1) : Long.valueOf(0); - return result; + return template.opsForSet().remove(key, value);// ? Long.valueOf(1) : Long.valueOf(0); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIsEmpty(java.lang.String) + */ + @Override @Transactional public Boolean getSetIsEmpty( final String key ) { Long result = template.opsForSet().size(key);// ? Long.valueOf(1) : Long.valueOf(0); return (result <= 0); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetValueAndGetSize(java.lang.String, java.lang.Object) + */ + @Override @Transactional public Long removeSetValueAndGetSize( final String key, final Object value ) { SetOperations setOps = template.opsForSet(); @@ -218,6 +315,10 @@ public Long removeSetValueAndGetSize( final String key, final Object value ) { return setOps.size(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetsValue(java.util.Collection, java.lang.Object) + */ + @Override public void removeSetsValue( final Collection keys, final Object value ) { SetOperations setOps = template.opsForSet(); Iterator itrKeys = keys.iterator(); @@ -231,6 +332,10 @@ public void removeSetsValue( final Collection keys, final Obje } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetsValue(java.lang.String, java.util.Collection, java.lang.Object) + */ + @Override public void removeSetsValue( final String keysPrefix, final Collection keys, final Object value ) { SetOperations setOps = template.opsForSet(); Iterator itrKeys = keys.iterator(); @@ -244,7 +349,7 @@ public void removeSetsValue( final String keysPrefix, final Collection keys(String pattern) { // Set result = template.keys(pattern); // log.info("Keys: " + ++keysCount); @@ -252,16 +357,28 @@ public void removeSetsValue( final String keysPrefix, final Collection hashOps = template.opsForHash(); @@ -271,22 +388,45 @@ public void swapHashKey( final String key, final String oldHashKey, final String } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#renameIfAbsent(java.lang.String, java.lang.String) + */ + @Override public Boolean renameIfAbsent(String oldKey, String newKey) { return template.renameIfAbsent(oldKey, newKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#rename(java.lang.String, java.lang.String) + */ + @Override public void rename(String oldKey, String newKey) { template.rename(oldKey, newKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setUnionAndStore(java.lang.String, java.lang.String, java.lang.String) + */ + @Override public Long setUnionAndStore(String key, String otherKey, String destKey) { return template.opsForSet().unionAndStore(key, otherKey, destKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setUnionAndStore(java.lang.String, java.util.Collection, java.lang.String) + */ + @Override public Long setUnionAndStore(String key, Collection otherKeys, String destKey) { return template.opsForSet().unionAndStore(key, otherKeys, destKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#removeSetValues(java.lang.String, java.util.Collection) + */ + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeSetValues(java.lang.String, java.util.Collection) + */ + @Override @Transactional public void removeSetValues( final String key, final Collection values ) { SetOperations setOps = template.opsForSet(); @@ -301,10 +441,21 @@ public void removeSetValues( final String key, final Collection getSetValue( final String key ) { return template.opsForSet().members(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#replaceSet(java.lang.String, java.util.Collection) + */ + @Override @Transactional public Long replaceSet( final String key, Collection values ) { template.delete(key); @@ -316,6 +467,13 @@ public Long replaceSet( final String key, Collection values ) } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#swapSetValue(java.lang.String, java.lang.String, java.lang.String) + */ + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#swapSetValue(java.lang.String, java.lang.String, java.lang.String) + */ + @Override @Transactional public void swapSetValue( final String key, final String oldValue, final String newValue ) { SetOperations setOps = template.opsForSet(); @@ -325,10 +483,18 @@ public void swapSetValue( final String key, final String oldValue, final String } } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIsMember(java.lang.String, java.lang.Object) + */ + @Override public Boolean getSetIsMember( final String key, final Object object ) { return template.opsForSet().isMember(key, object); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetsContainsMembers(java.util.Collection, java.lang.Object[]) + */ + @Override @Transactional public Set getSetsContainsMembers( final Collection keys, final Object[] membersToCheck ) { SetOperations setOps = template.opsForSet(); @@ -345,30 +511,105 @@ public Set getSetsContainsMembers( final Collection ke return intersectingMembers; } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIntersect(java.lang.String, java.util.Collection) + */ + @Override public Set getSetIntersect( final String key, Collection otherKeys ) { return template.opsForSet().intersect(key, otherKeys); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetIntersect(java.lang.String, java.lang.String) + */ + @Override public Set getSetIntersect( final String key, String otherKey ) { return template.opsForSet().intersect(key, otherKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetUnion(java.lang.String, java.util.Collection) + */ + @Override public Set getSetUnion( final String key, final Collection otherKeys ) { return template.opsForSet().union(key, otherKeys); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSetUnion(java.lang.String, java.lang.String) + */ + @Override public Set getSetUnion( final String key, final String otherKey ) { return template.opsForSet().union(key, otherKey); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#deleteKey(java.lang.String) + */ + @Override public void deleteKey( final String key ) { template.delete(key); } + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#deleteKeys(java.util.Collection) + */ + @Override public void deleteKeys( final Collection keys ) { if (keys != null && !keys.isEmpty()) { template.delete(keys); } } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#setSetValue(java.lang.String, java.lang.Object) + */ + @Override + @Transactional + public Long setSetValue(String key, Object value) { + return template.opsForSet().add(key, value);// ? Long.valueOf(1) : Long.valueOf(0); + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getSet(java.lang.String) + */ + @Override + public SetOperations getSet(String key) { + return template.opsForSet(); + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#getTemplate() + */ + @Override + public RedisTemplate getTemplate() { + return template; + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#keys(java.lang.String) + */ + @Override + public Collection keys(String pattern) { + return template.keys(pattern); + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisCacheDataStore#removeKeysValue(java.lang.String, java.lang.Object) + */ + @Override + @Transactional + public void removeKeysValue(String pattern, Object value) { + Set keys = template.keys(pattern); + Iterator itrKeys = keys.iterator(); + + while(itrKeys.hasNext()) { + try { + template.opsForSet().remove(itrKeys.next(), value); + } catch(Exception e) { + log.error("Error removing KeysValue", e); + } + } + } } diff --git a/src/main/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStore.java b/src/main/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStore.java new file mode 100644 index 0000000..a357f8c --- /dev/null +++ b/src/main/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStore.java @@ -0,0 +1,136 @@ +package com.percero.agents.sync.datastore; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.springframework.data.redis.core.SetOperations; +import org.springframework.stereotype.Component; + +@Component +public class RedisClusterCacheDataStore extends RedisCacheDataStore /*implements IRedisClusterCacheDataStore*/ { + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#setUnionAndStore(java.lang.String, java.lang.String, java.lang.String) + */ + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisClusterCacheDataStore#setUnionAndStore(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public Long setUnionAndStore(String key, String otherKey, String destKey) { + SetOperations setOps = template.opsForSet(); + Set existingSet = setOps.members(key); + existingSet.addAll(setOps.members(otherKey)); + + Iterator itr = existingSet.iterator(); + while(itr.hasNext()) { + setOps.add(destKey, itr.next()); + } + + return setOps.size(destKey); + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#setUnionAndStore(java.lang.String, java.util.Collection, java.lang.String) + */ + @Override + public Long setUnionAndStore(String key, Collection otherKeys, String destKey) { + SetOperations setOps = template.opsForSet(); + Set existingSet = setOps.members(key); + + Iterator itrKeys = otherKeys.iterator(); + while(itrKeys.hasNext()) { + String nextKey = itrKeys.next(); + + existingSet.addAll(setOps.members(nextKey)); + + Iterator itr = existingSet.iterator(); + while(itr.hasNext()) { + setOps.add(destKey, itr.next()); + } + } + + return setOps.size(destKey); + } + + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetIntersect(java.lang.String, java.util.Collection) + */ + @Override + public Set getSetIntersect( final String key, Collection otherKeys ) { + SetOperations setOps = template.opsForSet(); + + Set result = setOps.members(key); + + Iterator itrKeys = otherKeys.iterator(); + + while(itrKeys.hasNext()) { + String nextKey = itrKeys.next(); + Set otherSet = setOps.members(nextKey); + + Iterator itr = result.iterator(); + + while(itr.hasNext()) { + Object nextObject = itr.next(); + if (!otherSet.contains(nextObject)) { + itr.remove(); + } + } + } + + return result; + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetIntersect(java.lang.String, java.lang.String) + */ + @Override + public Set getSetIntersect( final String key, String otherKey ) { + SetOperations setOps = template.opsForSet(); + + Set theSet = setOps.members(key); + Set otherSet = setOps.members(otherKey); + Set result = new HashSet(); + + Iterator itr = theSet.iterator(); + + while(itr.hasNext()) { + Object nextObject = itr.next(); + if (otherSet.contains(nextObject)) { + result.add(nextObject); + } + } + + return result; + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetUnion(java.lang.String, java.util.Collection) + */ + @Override + public Set getSetUnion( final String key, final Collection otherKeys ) { + SetOperations setOps = template.opsForSet(); + + Set theSet = setOps.members(key); + Iterator itr = otherKeys.iterator(); + while(itr.hasNext()) { + theSet.addAll(setOps.members(itr.next())); + } + return theSet; + } + + /* (non-Javadoc) + * @see com.percero.agents.sync.datastore.IRedisDataStore#getSetUnion(java.lang.String, java.lang.String) + */ + @Override + public Set getSetUnion( final String key, final String otherKey ) { + SetOperations setOps = template.opsForSet(); + + Set theSet = setOps.members(key); + theSet.addAll(setOps.members(otherKey)); + return theSet; + } + +} diff --git a/src/main/java/com/percero/agents/sync/datastore/RedisClusterDataStore.java b/src/main/java/com/percero/agents/sync/datastore/RedisClusterDataStore.java deleted file mode 100644 index f61e85a..0000000 --- a/src/main/java/com/percero/agents/sync/datastore/RedisClusterDataStore.java +++ /dev/null @@ -1,257 +0,0 @@ -package com.percero.agents.sync.datastore; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.apache.log4j.Logger; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.SetOperations; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -import com.percero.agents.sync.services.PerceroRedisTemplate; - -@Component -public class RedisClusterDataStore { - - private static Logger log = Logger.getLogger(RedisClusterDataStore.class); - - @Autowired - private PerceroRedisTemplate template; - - public Boolean expire( final String key, final long timeout, final TimeUnit timeUnit ) { - return template.expire(key, timeout, timeUnit); - } - - public Object getValue( final String key ) { - return template.opsForValue().get( key ); - } - - public void setValue( final String key, final Object value ) { - template.opsForValue().set( key, value ); - } - - @Transactional - public Long setSetValue( final String key, final Object value ) { - return template.opsForSet().add(key, value);// ? Long.valueOf(1) : Long.valueOf(0); - } - - @Transactional - public Long lpushListValue( final String key, final Object value ) { - return template.opsForList().leftPush(key, value); - } - - @Transactional - public List listAll( final String key) { - return listRange(key, Long.valueOf(0), Long.valueOf(-1)); - } - - @Transactional - public List listRange( final String key, final Long start, final Long end ) { - return template.opsForList().range(key, start, end); - } - - @Transactional - public Object listIndex( final String key, final Long index ) { - return template.opsForList().index(key, index); - } - - @Transactional - public Object listIndex( final String key ) { - return template.opsForList().index(key, Long.valueOf(0)); - } - - @Transactional - public void setHashValue( final String key, final String hashKey, final Object value ) { - template.opsForHash().put(key, hashKey, value); - } - - @Transactional - public Long removeSetValue( final String key, final Object value ) { - return template.opsForSet().remove(key, value);// ? Long.valueOf(1) : Long.valueOf(0); - } - - public void removeSetsValue( final Collection keys, final Object value ) { - SetOperations setOps = template.opsForSet(); - Iterator itrKeys = keys.iterator(); - while(itrKeys.hasNext()) { - String nextKey = itrKeys.next(); - setOps.remove(nextKey, value); - } - } - - public SetOperations getSet( final String key ) { - return template.opsForSet(); - } - - public RedisTemplate getTemplate() { - return template; - } - - public Collection keys(String pattern) { - return template.keys(pattern); - } - - public Boolean renameIfAbsent(String oldKey, String newKey) { - return template.renameIfAbsent(oldKey, newKey); - } - - public void rename(String oldKey, String newKey) { - template.rename(oldKey, newKey); - } - - public Long setUnionAndStore(String key, String otherKey, String destKey) { - SetOperations setOps = template.opsForSet(); - Set existingSet = setOps.members(key); - existingSet.addAll(setOps.members(otherKey)); - - Iterator itr = existingSet.iterator(); - while(itr.hasNext()) { - setOps.add(destKey, itr.next()); - } - - return setOps.size(destKey); - } - - public Long setUnionAndStore(String key, Collection otherKeys, String destKey) { - SetOperations setOps = template.opsForSet(); - Set existingSet = setOps.members(key); - - Iterator itrKeys = otherKeys.iterator(); - while(itrKeys.hasNext()) { - String nextKey = itrKeys.next(); - - existingSet.addAll(setOps.members(nextKey)); - - Iterator itr = existingSet.iterator(); - while(itr.hasNext()) { - setOps.add(destKey, itr.next()); - } - } - - return setOps.size(destKey); - } - - @Transactional - public void removeKeysValue( final String pattern, final Object value ) { - Set keys = template.keys(pattern); - Iterator itrKeys = keys.iterator(); - - while(itrKeys.hasNext()) { - try { - template.opsForSet().remove(itrKeys.next(), value); - } catch(Exception e) { - log.error("Error removing KeysValue", e); - } - } - } - - @Transactional - public void removeSetValues( final String key, final Collection values ) { - SetOperations setOps = template.opsForSet(); - - Iterator itrValues = values.iterator(); - while(itrValues.hasNext()) { - try { - setOps.remove(key, itrValues.next()); - } catch(Exception e) { - log.error("Unable to remove Set Value", e); - } - } - } - - public Set getSetValue( final String key ) { - template.opsForSet().members(key); - return template.opsForSet().members(key); - } - - @Transactional - public void swapSetValue( final String key, final String oldValue, final String newValue ) { - SetOperations setOps = template.opsForSet(); - if (setOps.isMember(key, oldValue)) { - setOps.remove(key, oldValue); - setOps.add(key, newValue); - } - } - - public Boolean getSetIsMember( final String key, final Object object ) { - - return template.opsForSet().isMember(key, object); - } - - public Set getSetIntersect( final String key, Collection otherKeys ) { - SetOperations setOps = template.opsForSet(); - - Set result = setOps.members(key); - - Iterator itrKeys = otherKeys.iterator(); - - while(itrKeys.hasNext()) { - String nextKey = itrKeys.next(); - Set otherSet = setOps.members(nextKey); - - Iterator itr = result.iterator(); - - while(itr.hasNext()) { - Object nextObject = itr.next(); - if (!otherSet.contains(nextObject)) { - itr.remove(); - } - } - } - - return result; - } - - public Set getSetIntersect( final String key, String otherKey ) { - SetOperations setOps = template.opsForSet(); - - Set theSet = setOps.members(key); - Set otherSet = setOps.members(otherKey); - Set result = new HashSet(); - - Iterator itr = theSet.iterator(); - - while(itr.hasNext()) { - Object nextObject = itr.next(); - if (otherSet.contains(nextObject)) { - result.add(nextObject); - } - } - - return result; - } - - public Set getSetUnion( final String key, final Collection otherKeys ) { - SetOperations setOps = template.opsForSet(); - - Set theSet = setOps.members(key); - Iterator itr = otherKeys.iterator(); - while(itr.hasNext()) { - theSet.addAll(setOps.members(itr.next())); - } - return theSet; - } - - public Set getSetUnion( final String key, final String otherKey ) { - SetOperations setOps = template.opsForSet(); - - Set theSet = setOps.members(key); - theSet.addAll(setOps.members(otherKey)); - return theSet; - } - - public void deleteKey( final String key ) { - template.delete(key); - } - - public void deleteKeys( final Collection keys ) { - if (keys.size() > 0) - template.delete(keys); - } -} diff --git a/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java b/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java index 36ead6e..117877e 100644 --- a/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/PostPutHelper.java @@ -84,7 +84,7 @@ public void postPutObject(ClassIDPair pair, String pusherUserId, String pusherCl // Now run past the ChangeWatcher. - if (changedFields == null) { + if (changedFields == null || changedFields.isEmpty()) { accessManager.checkChangeWatchers(pair, null, null); } else { diff --git a/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java b/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java index 2f3934b..dca6fe0 100644 --- a/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java +++ b/src/main/java/com/percero/agents/sync/helpers/RedisPostClientHelper.java @@ -2,7 +2,6 @@ import java.util.Collection; import java.util.Iterator; -import java.util.Set; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; @@ -12,7 +11,7 @@ import com.percero.agents.sync.access.IAccessManager; import com.percero.agents.sync.access.RedisKeyUtils; -import com.percero.agents.sync.datastore.RedisDataStore; +import com.percero.agents.sync.datastore.ICacheDataStore; @Component public class RedisPostClientHelper { @@ -20,7 +19,7 @@ public class RedisPostClientHelper { private static final Logger log = Logger.getLogger(RedisPostClientHelper.class); @Autowired - private RedisDataStore redisDataStore; + private ICacheDataStore cacheDataStore; @Autowired IAccessManager accessManager; @@ -34,11 +33,11 @@ public void setUserDeviceTimeout(Long value) { @Transactional public void postClient(String clientId) throws Exception { // Get the client's userId. - String userId = (String) redisDataStore.getValue(RedisKeyUtils.client(clientId)); + String userId = (String) cacheDataStore.getValue(RedisKeyUtils.client(clientId)); if (userId != null && userId.length() > 0) { // Timeout Client's User ID. - redisDataStore.expire(RedisKeyUtils.client(clientId), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(RedisKeyUtils.client(clientId), userDeviceTimeout, TimeUnit.SECONDS); // Remove from NonPersistent Clients //redisDataStore.removeSetValue(RedisKeyUtils.clientsNonPersistent(), clientId); @@ -47,13 +46,13 @@ public void postClient(String clientId) throws Exception { //redisDataStore.removeSetValue(RedisKeyUtils.clientsPersistent(), clientId); // Timeout Client User - redisDataStore.expire(RedisKeyUtils.clientUser(userId), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(RedisKeyUtils.clientUser(userId), userDeviceTimeout, TimeUnit.SECONDS); // Timeout UpdateJournals for this Client. - redisDataStore.expire(RedisKeyUtils.updateJournal(clientId), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(RedisKeyUtils.updateJournal(clientId), userDeviceTimeout, TimeUnit.SECONDS); // Timeout DeleteJournals for this Client. - redisDataStore.expire(RedisKeyUtils.deleteJournal(clientId), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(RedisKeyUtils.deleteJournal(clientId), userDeviceTimeout, TimeUnit.SECONDS); // // Timeout TransactionJournals for this Client. // Collection transJournalKeys = redisDataStore.keys(RedisKeyUtils.transactionJournal(clientId, "*")); @@ -65,13 +64,13 @@ public void postClient(String clientId) throws Exception { // Timeout Client's UserDevice. // Collection userDeviceKeys = redisDataStore.keys(RedisKeyUtils.userDevice(userId, "*")); // TODO: This expire no longer works!!! - Collection userDeviceKeys = redisDataStore.getHashKeys(RedisKeyUtils.userDeviceHash(userId)); + Collection userDeviceKeys = cacheDataStore.getHashKeys(RedisKeyUtils.userDeviceHash(userId)); Iterator itrUserDevices = userDeviceKeys.iterator(); while (itrUserDevices.hasNext()) { String nextKey = (String) itrUserDevices.next(); - if (clientId.equals(redisDataStore.getValue(nextKey))) { - redisDataStore.expire(RedisKeyUtils.deviceHash(nextKey), userDeviceTimeout, TimeUnit.SECONDS); - redisDataStore.expire(nextKey, userDeviceTimeout, TimeUnit.SECONDS); + if (clientId.equals(cacheDataStore.getValue(nextKey))) { + cacheDataStore.expire(RedisKeyUtils.deviceHash(nextKey), userDeviceTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(nextKey, userDeviceTimeout, TimeUnit.SECONDS); } } } diff --git a/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java b/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java index 69d24a8..edb4ed9 100644 --- a/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java +++ b/src/main/java/com/percero/agents/sync/services/ISyncAgentService.java @@ -52,7 +52,7 @@ public interface ISyncAgentService { public Object findUnique(Object theQueryObject, String clientId) throws Exception; public Object runQuery(String className, String queryName, Object[] queryArguments, String clientId) throws Exception; public Object runProcess(String processName, Object[] queryArguments, String clientId) throws Exception; - public Object getChangeWatcher(ClassIDPair classIdPair, String fieldName, String[] params, String clientId) throws Exception; + public Object getChangeWatcherValue(ClassIDPair classIdPair, String fieldName, String[] params, String clientId) throws Exception; public List getHistory(String aClassName, String anId, String clientId) throws Exception; public Object searchByExample(Object theQueryObject, String clientId) throws Exception; diff --git a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java b/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java index d933039..e74656b 100644 --- a/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java +++ b/src/main/java/com/percero/agents/sync/services/SyncAgentDataProvider.java @@ -37,7 +37,7 @@ import org.springframework.util.StringUtils; import com.percero.agents.sync.access.RedisKeyUtils; -import com.percero.agents.sync.datastore.RedisDataStore; +import com.percero.agents.sync.datastore.ICacheDataStore; import com.percero.agents.sync.exceptions.SyncDataException; import com.percero.agents.sync.exceptions.SyncException; import com.percero.agents.sync.hibernate.AssociationExample; @@ -77,7 +77,7 @@ public String getName() { } @Autowired - RedisDataStore redisDataStore; + ICacheDataStore cacheDataStore; @Autowired Long cacheTimeout = Long.valueOf(60 * 60 * 24 * 14); // Two weeks @@ -463,7 +463,7 @@ public IPerceroObject systemGetById(ClassIDPair classIdPair) { key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); if (cacheTimeout > 0) - redisDataStore.setValue(key, ((BaseDataObject)result).toJson()); + cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); } else { // Not necessarily a problem but could be helpful when debugging. @@ -476,7 +476,7 @@ public IPerceroObject systemGetById(ClassIDPair classIdPair) { // (Re)Set the expiration. if (cacheTimeout > 0 && key != null) { - redisDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); } return result; @@ -514,7 +514,7 @@ public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, key = RedisKeyUtils.classIdPair(result.getClass().getCanonicalName(), result.getID()); result = (IPerceroObject) SyncHibernateUtils.cleanObject(result, s); if (cacheTimeout > 0) - redisDataStore.setValue(key, ((BaseDataObject)result).toJson()); + cacheDataStore.setValue(key, ((BaseDataObject)result).toJson()); } else { log.warn("Unable to retrieve object from database: " + classIdPair.toString()); @@ -526,7 +526,7 @@ public IPerceroObject systemGetByIdWithClassAndSession(ClassIDPair classIdPair, // (Re)Set the expiration. if (cacheTimeout > 0 && key != null) { - redisDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); } return result; @@ -555,7 +555,7 @@ private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Ex MappedClass mc = mcm.getMappedClassByClassName(classIdPair.getClassName()); String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); - String jsonObjectString = (String) redisDataStore.getValue(key); + String jsonObjectString = (String) cacheDataStore.getValue(key); if (jsonObjectString != null) { if (IJsonObject.class.isAssignableFrom(theClass)) { IJsonObject jsonObject = (IJsonObject) theClass.newInstance(); @@ -572,7 +572,7 @@ private IPerceroObject retrieveFromRedisCache(ClassIDPair classIdPair) throws Ex while (itrChildMappedClasses.hasNext()) { MappedClass nextChildMc = itrChildMappedClasses.next(); key = RedisKeyUtils.classIdPair(nextChildMc.className, classIdPair.getID()); - jsonObjectString = (String) redisDataStore.getValue(key); + jsonObjectString = (String) cacheDataStore.getValue(key); if (jsonObjectString != null) { result = (IPerceroObject) safeObjectMapper.readValue(jsonObjectString, theClass); return result; @@ -614,7 +614,7 @@ private Map retrieveFromRedisCache(ClassIDPairs classIdP } // String key = RedisKeyUtils.classIdPair(classIdPair.getClassName(), classIdPair.getID()); - List jsonObjectStrings = redisDataStore.getValues(keys); + List jsonObjectStrings = cacheDataStore.getValues(keys); Iterator itrJsonObjectStrings = jsonObjectStrings.iterator(); while (itrJsonObjectStrings.hasNext()) { String jsonObjectString = (String) itrJsonObjectStrings.next(); @@ -646,7 +646,7 @@ private Map retrieveFromRedisCache(ClassIDPairs classIdP } if (pleaseSetTimeout) { - redisDataStore.expire(keys, cacheTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(keys, cacheTimeout, TimeUnit.SECONDS); } } @@ -873,9 +873,9 @@ public List findByIds(ClassIDPairs classIdPairs, String userId) } // Store the objects in redis. - redisDataStore.setValues(mapJsonObjectStrings); + cacheDataStore.setValues(mapJsonObjectStrings); // (Re)Set the expiration. - redisDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); + cacheDataStore.expire(mapJsonObjectStrings.keySet(), cacheTimeout, TimeUnit.SECONDS); } if (result == null) { @@ -1080,8 +1080,8 @@ public IPerceroObject systemCreateObject(IPerceroObject perceroObject) if (cacheTimeout > 0) { String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); if (cacheTimeout > 0) { - redisDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); - redisDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + cacheDataStore.expire(key, cacheTimeout, TimeUnit.SECONDS); } Set keysToDelete = new HashSet(); @@ -1130,7 +1130,7 @@ else if (fieldObject instanceof Collection) { } if (!keysToDelete.isEmpty()) { - redisDataStore.deleteKeys(keysToDelete); + cacheDataStore.deleteKeys(keysToDelete); // TODO: Do we simply delete the key? Or do we refetch the object here and update the key? //redisDataStore.setValue(nextKey, ((BaseDataObject)perceroObject).toJson()); } @@ -1284,8 +1284,8 @@ public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map 0) { // TODO: Also need to update the caches of anything object that is related to this object. String key = RedisKeyUtils.classIdPair(perceroObject.getClass().getCanonicalName(), perceroObject.getID()); - if (redisDataStore.hasKey(key)) { - redisDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); + if (cacheDataStore.hasKey(key)) { + cacheDataStore.setValue(key, ((BaseDataObject)perceroObject).toJson()); } // Iterate through each changed object and reset the cache for that object. @@ -1311,7 +1311,7 @@ public IPerceroObject systemPutObject(IPerceroObject perceroObject, Map getHistory(String aClassName, String anId, String clientId) if (hasReadAccess) { // Get the Historical Objects. - return redisDataStore.listAll(RedisKeyUtils.historicalObject(aClassName, anId)); + return cacheDataStore.listAll(RedisKeyUtils.historicalObject(aClassName, anId)); } return null; @@ -647,7 +645,7 @@ public ServerResponse putObject(IPerceroObject perceroObject, String transaction // Get the most recent ObjectModJournal, only if the UpdateDate is set. if (updateDate != null) { try { - objectModJournal = (ObjectModJournal) redisDataStore.listIndex(RedisKeyUtils.objectModJournal(perceroObject.getClass().getName(), perceroObject.getID())); + objectModJournal = (ObjectModJournal) cacheDataStore.listIndex(RedisKeyUtils.objectModJournal(perceroObject.getClass().getName(), perceroObject.getID())); } catch(Exception e) { log.warn("Unable to retrieve most recent objectModJournal", e); } @@ -694,7 +692,7 @@ public ServerResponse putObject(IPerceroObject perceroObject, String transaction newModJournal.setClassID(result.getID()); newModJournal.setClassName(result.getClass().getName()); - redisDataStore.lpushListValue(RedisKeyUtils.objectModJournal(perceroObject.getClass().getCanonicalName(), perceroObject.getID()), newModJournal); + cacheDataStore.lpushListValue(RedisKeyUtils.objectModJournal(perceroObject.getClass().getCanonicalName(), perceroObject.getID()), newModJournal); // Also store historical record, if necessary. // Get the Current object if this is a BaseHistoryObject. @@ -709,7 +707,7 @@ public ServerResponse putObject(IPerceroObject perceroObject, String transaction historyObject.setObjectChangerId(userId); historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); - redisDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); } if (taskExecutor != null && false) { @@ -757,7 +755,7 @@ public boolean systemPutObject(IPerceroObject perceroObject, String transactionI try { // Get the most recent ObjectModJournal. try { - objectModJournal = (ObjectModJournal) redisDataStore.listIndex(RedisKeyUtils.objectModJournal(perceroObject.getClass().getName(), perceroObject.getID())); + objectModJournal = (ObjectModJournal) cacheDataStore.listIndex(RedisKeyUtils.objectModJournal(perceroObject.getClass().getName(), perceroObject.getID())); } catch(Exception e) { log.warn("Unable to retrieve most recent objectModJournal", e); } @@ -797,7 +795,7 @@ public boolean systemPutObject(IPerceroObject perceroObject, String transactionI newModJournal.setClassName(result.getClass().getName()); newModJournal.setDateModified(updateDate); - redisDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); + cacheDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); // Also store historical record, if necessary. // Get the Current object if this is a BaseHistoryObject. @@ -812,7 +810,7 @@ public boolean systemPutObject(IPerceroObject perceroObject, String transactionI historyObject.setObjectChangerId(userId); historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); - redisDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); //syncSession.save(historyObject); } @@ -875,7 +873,7 @@ public ServerResponse createObject(IPerceroObject perceroObject, String clientId newModJournal.setClassName(result.getClass().getName()); try { - redisDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); + cacheDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); } catch(Exception e) { log.error("Unable to save mod journal to redis cache", e); } @@ -894,7 +892,7 @@ public ServerResponse createObject(IPerceroObject perceroObject, String clientId historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); try { - redisDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); } catch(Exception e) { log.error("Unable to save history object to redis cache", e); } @@ -956,7 +954,7 @@ public T systemCreateObject(IPerceroObject perceroObj newModJournal.setClassName(result.getClass().getName()); try { - redisDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); + cacheDataStore.lpushListValue(RedisKeyUtils.objectModJournal(result.getClass().getCanonicalName(), result.getID()), newModJournal); } catch(Exception e) { log.error("Unable to save mod journal to redis cache", e); } @@ -975,7 +973,7 @@ public T systemCreateObject(IPerceroObject perceroObj historyObject.setObjectData(safeObjectMapper.writeValueAsString(result)); try { - redisDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(result.getClass().getCanonicalName(), result.getID()), historyObject); } catch(Exception e) { log.error("Unable to save history object to redis cache", e); } @@ -1213,7 +1211,7 @@ else if (nextToManyField instanceof MappedFieldList) { historyObject.setObjectChangerId(userId); historyObject.setObjectData(safeObjectMapper.writeValueAsString(perceroObject)); - redisDataStore.lpushListValue(RedisKeyUtils.historicalObject(perceroObject.getClass().getCanonicalName(), perceroObject.getID()), historyObject); + cacheDataStore.lpushListValue(RedisKeyUtils.historicalObject(perceroObject.getClass().getCanonicalName(), perceroObject.getID()), historyObject); } catch(Exception e) { log.warn("Unable to save HistoricalObject in deleteObject", e); } diff --git a/src/main/java/com/percero/amqp/AuthAgentListener.java b/src/main/java/com/percero/amqp/AuthAgentListener.java deleted file mode 100644 index 13a52ed..0000000 --- a/src/main/java/com/percero/amqp/AuthAgentListener.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.percero.amqp; - -import org.apache.log4j.Logger; -import org.springframework.amqp.core.AmqpTemplate; -import org.springframework.amqp.core.Message; -import org.springframework.amqp.core.MessageListener; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; - -import com.percero.agents.auth.hibernate.AuthHibernateUtils; -import com.percero.agents.auth.services.IAuthService; -import com.percero.agents.auth.vo.AuthProvider; -import com.percero.agents.auth.vo.AuthRequest; -import com.percero.agents.auth.vo.AuthResponse; -import com.percero.agents.auth.vo.AuthenticateOAuthAccessTokenRequest; -import com.percero.agents.auth.vo.AuthenticateOAuthAccessTokenResponse; -import com.percero.agents.auth.vo.AuthenticateOAuthCodeRequest; -import com.percero.agents.auth.vo.AuthenticateOAuthCodeResponse; -import com.percero.agents.auth.vo.DisconnectRequest; -import com.percero.agents.auth.vo.DisconnectResponse; -import com.percero.agents.auth.vo.OAuthResponse; -import com.percero.agents.auth.vo.OAuthToken; -import com.percero.agents.auth.vo.ValidateUserByTokenRequest; -import com.percero.agents.auth.vo.ValidateUserByTokenResponse; -import com.percero.serial.IDecoder; - -/** - * This class supplies the main method that creates the spring context - * and then all processing is invoked asynchronously by messaging. - * - * This class' onMessage function will be invoked when the process receives a message from the broker - * @author Jonathan Samples - * - */ -//@Component("authAgentListener") -public class AuthAgentListener implements MessageListener{ - - @Autowired - AmqpTemplate template; - @Autowired - IDecoder decoder; - @Autowired - IAuthService authService; - - private static Logger logger = Logger.getLogger("com.percero"); - - /** - * Message handling function - */ - @SuppressWarnings("unchecked") - @Transactional - public void onMessage(Message message) { - Object result = "INVALID DEFAULT VALUE"; - AuthRequest request = null; - AuthResponse response = null; - try{ - Object ob = decoder.decode(message.getBody()); - if (ob instanceof AuthRequest) - request = (AuthRequest) ob; - - String key = message.getMessageProperties().getReceivedRoutingKey(); - //String userId = message.getMessageProperties().getUserId(); - - /** Essentially, Re-login **/ - if(key.equals(ValidateUserByTokenRequest.ID) || key.equals("validateUserByToken")){ - if (request instanceof ValidateUserByTokenRequest) { - ValidateUserByTokenRequest authRequest = (ValidateUserByTokenRequest) request; - result = authService.validateUserByToken(authRequest.getRegAppKey(), authRequest.getUserId(), authRequest.getToken(), authRequest.getClientId()); - response = new ValidateUserByTokenResponse(); - result = AuthHibernateUtils.cleanObject(result); - ((ValidateUserByTokenResponse) response).setResult((Boolean)result); - } - } - /** For OAuth2 WebApp style **/ - else if(key.equals(AuthenticateOAuthCodeRequest.ID) || key.equals("authenticateOAuthCode")){ - if (request instanceof AuthenticateOAuthCodeRequest) { - AuthenticateOAuthCodeRequest authRequest = (AuthenticateOAuthCodeRequest) request; - OAuthToken token = new OAuthToken(); - token.setToken(authRequest.getRequestToken()); - token.setTokenSecret(authRequest.getRequestSecret()); - AuthProvider authProvider = authRequest.getAuthProvider(); - - result = authService.authenticateOAuthCode(authProvider, authRequest.getCode(), message.getMessageProperties().getReplyTo(), authRequest.getDeviceId(), authRequest.getRedirectUri(), token); - response = new AuthenticateOAuthCodeResponse(); - - if (result != null) { - result = AuthHibernateUtils.cleanObject(result); - ((AuthenticateOAuthCodeResponse) response).setResult(((OAuthResponse)result).userToken); - ((AuthenticateOAuthCodeResponse) response).setAccessToken(((OAuthResponse)result).accessToken); - ((AuthenticateOAuthCodeResponse) response).setRefreshToken(((OAuthResponse)result).refreshToken); - } - } - } - /** For OAuth2 Installed App style - @DEPRICATED **/ - else if(key.equals(AuthenticateOAuthAccessTokenRequest.ID) || key.equals("authenticateOAuthAccessToken")){ - if (request instanceof AuthenticateOAuthAccessTokenRequest) { - AuthenticateOAuthAccessTokenRequest authRequest = (AuthenticateOAuthAccessTokenRequest) request; - AuthProvider authProvider = authRequest.getAuthProvider(); - result = authService.authenticateOAuthAccessToken(authProvider, authRequest.getAccessToken(), authRequest.getRefreshToken(), message.getMessageProperties().getReplyTo(), authRequest.getDeviceId()); - response = new AuthenticateOAuthAccessTokenResponse(); - result = AuthHibernateUtils.cleanObject(result); - if (result != null) { - ((AuthenticateOAuthAccessTokenResponse) response).setResult(((OAuthResponse)result).userToken); - ((AuthenticateOAuthAccessTokenResponse) response).setAccessToken(((OAuthResponse)result).accessToken); - ((AuthenticateOAuthAccessTokenResponse) response).setRefreshToken(((OAuthResponse)result).refreshToken); - } - } - } - // This can be removed -// else if(key.equals("authenticateUserAccount")){ -// if (request instanceof AuthenticateUserAccountRequest) { -// AuthenticateUserAccountRequest authReqest = (AuthenticateUserAccountRequest) request; -// result = authService.authenticateUserAccount(authReqest.getRegAppKey(), authReqest.getSvcOauthKey(), authReqest.getUserAccount(), request.getClientId(), authReqest.getDeviceId()); -// response = new AuthenticateUserAccountResponse(); -// result = AuthHibernateUtils.cleanObject(result); -// ((AuthenticateUserAccountResponse) response).setResult((UserToken)result); -// } -// } - // Removable -// else if(key.equals("getRegisteredApplication")){ -// if (request instanceof GetRegisteredApplicationRequest) { -// GetRegisteredApplicationRequest authRequest = (GetRegisteredApplicationRequest) request; -// result = authService.getRegisteredApplication(authRequest.getAppKey()); -// response = new GetRegisteredApplicationResponse(); -// ((GetRegisteredApplicationResponse)response).setResult((RegisteredApplication)result); -// } -// else -// result = authService.getAllServiceProviders(); -// } - // Removable -// else if(key.equals("getRegAppOAuths")){ -// if (request instanceof GetRegAppOAuthsRequest) { -// GetRegAppOAuthsRequest authRequest = (GetRegAppOAuthsRequest) request; -// result = authService.getRegAppOAuths(authRequest.getRegAppKey(), authRequest.getRegAppSecret(), authRequest.getOauthType()); -// response = new GetRegAppOAuthsResponse(); -// ((GetRegAppOAuthsResponse)response).setResult((List)result); -// } -// } - // Removable -// else if(key.equals("getOAuthRequestToken")){ -// if (request instanceof GetOAuthRequestTokenRequest) { -// GetOAuthRequestTokenRequest authRequest = (GetOAuthRequestTokenRequest) request; -// result = authService.getOAuthRequestToken(authRequest.getRegAppKey(), authRequest.getSvcOauthKey()); -// response = new GetOAuthRequestTokenResponse(); -// ((GetOAuthRequestTokenResponse)response).setToken(((OAuthToken)result).getToken()); -// ((GetOAuthRequestTokenResponse)response).setTokenSecret(((OAuthToken)result).getTokenSecret()); -// ((GetOAuthRequestTokenResponse)response).setExpiresIn(((OAuthToken)result).getExpiresIn()); -// } -// } - // Removable -// else if(key.equals("getAllServiceProviders")){ -// if (request instanceof GetAllServiceProvidersRequest) { -// result = authService.getAllServiceProviders(); -// response = new GetAllServiceProvidersResponse(); -// ((GetAllServiceProvidersResponse)response).setResult((List)result); -// } -// else -// result = authService.getAllServiceProviders(); -// } - else if(key.equals("disconnectAuth")){ - if (request instanceof DisconnectRequest) { - response = new DisconnectResponse(); - result = authService.logoutUser(request.getUserId(), request.getToken(), request.getClientId()); - ((DisconnectResponse) response).setResult((Boolean)result); - } - } - else if(key.equals("testCall")){ -// result = authService.testCall((String)ob); - } - else{ - System.out.println("Unknown Message Type"); - } - } catch(Exception e){ - logger.error(e.getMessage(), e); - } finally{ - // Send a message back to the originator - if (request != null) - { - if (response == null) - response = new AuthResponse(); - response.setClientId(request.getClientId()); - response.setCorrespondingMessageId(request.getMessageId()); - template.convertAndSend(message.getMessageProperties().getReplyTo(), response); - } - else - template.convertAndSend(message.getMessageProperties().getReplyTo(), result); - } - } -} diff --git a/src/main/java/com/percero/amqp/PerceroAgentListener.java b/src/main/java/com/percero/amqp/PerceroAgentListener.java index d917d6b..d2974b5 100644 --- a/src/main/java/com/percero/amqp/PerceroAgentListener.java +++ b/src/main/java/com/percero/amqp/PerceroAgentListener.java @@ -2,6 +2,8 @@ import com.percero.agents.auth.helpers.IAccountHelper; import com.percero.agents.auth.hibernate.AuthHibernateUtils; +import com.percero.agents.auth.services.AuthProviderRegistry; +import com.percero.agents.auth.services.AuthService2; import com.percero.agents.auth.services.IAuthService; import com.percero.agents.auth.vo.*; import com.percero.agents.sync.access.IAccessManager; @@ -46,6 +48,8 @@ public class PerceroAgentListener implements MessageListener { @Autowired IAuthService authService; @Autowired + AuthService2 authService2; + @Autowired IAccessorService accessorService; @Autowired JsonMessageConverter jsonMessageConverter; @@ -103,6 +107,9 @@ public class PerceroAgentListener implements MessageListener { @Autowired GetHistoryHandler getHistoryHandler; + @Autowired + AuthProviderRegistry authProviderRegistry; + public static final String PROCESS_TRANSACTION = "processTransaction"; @@ -260,13 +267,19 @@ public void handleAuthRequest(AuthRequest request, String key, String replyTo) { Object result = "INVALID DEFAULT VALUE"; AuthResponse response = null; try{ - if(key.equals("authenticationRequest")){ - if(request instanceof AuthenticationRequest){ - AuthenticationRequest authRequest = (AuthenticationRequest) request; - } + /** authentication provider infrastructure **/ + if(key.equals("authenticate") && request instanceof AuthenticationRequest){ + AuthenticationRequest authRequest = (AuthenticationRequest) request; + response = authService2.authenticate(authRequest); + result = response; + } + else if(key.equals("reauthenticate") && request instanceof ReauthenticationRequest){ + ReauthenticationRequest authRequest = (ReauthenticationRequest) request; + response = authService2.reauthenticate(authRequest); + result = response; } /** Essentially, Re-login **/ - if(key.equals(ValidateUserByTokenRequest.ID) || key.equals("validateUserByToken")){ + else if(key.equals(ValidateUserByTokenRequest.ID) || key.equals("validateUserByToken")){ if (request instanceof ValidateUserByTokenRequest) { ValidateUserByTokenRequest authReqest = (ValidateUserByTokenRequest) request; result = authService.validateUserByToken(authReqest.getRegAppKey(), authReqest.getUserId(), authReqest.getToken(), authReqest.getClientId()); @@ -282,9 +295,9 @@ else if(key.equals(AuthenticateOAuthCodeRequest.ID) || key.equals("authenticateO OAuthToken token = new OAuthToken(); token.setToken(authRequest.getRequestToken()); token.setTokenSecret(authRequest.getRequestSecret()); - AuthProvider authProvider = authRequest.getAuthProvider(); + String authProviderID = authRequest.getAuthProvider(); - result = authService.authenticateOAuthCode(authProvider, authRequest.getCode(), replyTo, authRequest.getDeviceId(), authRequest.getRedirectUri(), token); + result = authService.authenticateOAuthCode(authProviderID, authRequest.getCode(), replyTo, authRequest.getDeviceId(), authRequest.getRedirectUri(), token); response = new AuthenticateOAuthCodeResponse(); if (result != null) { @@ -302,9 +315,9 @@ else if(key.equals("authenticateBasicOAuth")){ OAuthToken token = new OAuthToken(); token.setToken(authRequest.getRequestToken()); token.setTokenSecret(authRequest.getRequestSecret()); - AuthProvider authProvider = authRequest.getAuthProvider(); + String authProviderID = authRequest.getAuthProvider(); - result = authService.authenticateBasicOAuth(authProvider, authRequest.getUserName(), authRequest.getPassword(), authRequest.getScopes(), authRequest.getAppUrl(), replyTo, authRequest.getDeviceId(), token); + result = authService.authenticateBasicOAuth(authProviderID, authRequest.getUserName(), authRequest.getPassword(), authRequest.getScopes(), authRequest.getAppUrl(), replyTo, authRequest.getDeviceId(), token); response = new AuthenticateBasicOAuthResponse(); if (result != null) { @@ -319,8 +332,8 @@ else if(key.equals("authenticateBasicOAuth")){ else if(key.equals(AuthenticateOAuthAccessTokenRequest.ID) || key.equals("authenticateOAuthAccessToken")){ if (request instanceof AuthenticateOAuthAccessTokenRequest) { AuthenticateOAuthAccessTokenRequest authRequest = (AuthenticateOAuthAccessTokenRequest) request; - AuthProvider authProvider = authRequest.getAuthProvider(); - result = authService.authenticateOAuthAccessToken(authProvider, authRequest.getAccessToken(), authRequest.getRefreshToken(), replyTo, authRequest.getDeviceId()); + String authProviderID = authRequest.getAuthProvider(); + result = authService.authenticateOAuthAccessToken(authProviderID, authRequest.getAccessToken(), authRequest.getRefreshToken(), replyTo, authRequest.getDeviceId()); response = new AuthenticateOAuthAccessTokenResponse(); result = AuthHibernateUtils.cleanObject(result); if (result != null) { diff --git a/src/main/java/com/percero/amqp/SyncAgentListener.java b/src/main/java/com/percero/amqp/SyncAgentListener.java deleted file mode 100644 index 5f6362a..0000000 --- a/src/main/java/com/percero/amqp/SyncAgentListener.java +++ /dev/null @@ -1,453 +0,0 @@ -package com.percero.amqp; - -import com.percero.agents.auth.helpers.IAccountHelper; -import com.percero.agents.sync.access.IAccessManager; -import com.percero.agents.sync.exceptions.SyncException; -import com.percero.agents.sync.services.IPushSyncHelper; -import com.percero.agents.sync.services.ISyncAgentService; -import com.percero.agents.sync.vo.*; -import com.percero.framework.accessor.IAccessor; -import com.percero.framework.accessor.IAccessorService; -import com.percero.framework.vo.IPerceroObject; -import org.apache.log4j.Logger; -import org.codehaus.jackson.map.ObjectMapper; -import org.springframework.amqp.core.*; -import org.springframework.amqp.support.converter.JsonMessageConverter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; - -import java.security.Principal; -import java.util.*; - -/** - * This class supplies the main method that creates the spring context - * and then all processing is invoked asynchronously by messaging. - * - * This class' onMessage function will be invoked when the process receives a 'test' message from the broker - * @author Jonathan Samples - * - */ -//@Component("syncAgentListener") -public class SyncAgentListener implements MessageListener{ - - @Autowired - AmqpTemplate template; - @Autowired - AmqpAdmin amqpAdmin; - @Autowired - IDecoder decoder; - @Autowired - ISyncAgentService syncAgentService; - private Boolean manifestProcessed = true; // Turned off for now. - @Autowired - IAccessorService accessorService; - @Autowired - JsonMessageConverter jsonMessageConverter; - @Autowired - ObjectMapper safeObjectMapper; - @Autowired - IAccessManager accessManager; - @Autowired - IAccountHelper accountHelper; - @Autowired - IPushSyncHelper pushSyncHelper; - public void setPushSyncHelper(IPushSyncHelper value) { - pushSyncHelper = value; - } - - - public static final String CONNECT = "connect"; - public static final String HIBERNATE = "hibernate"; - public static final String UPGRADE_CLIENT = "upgradeClient"; - public static final String LOGOUT = "logout"; - public static final String DISCONNECT = "disconnect"; - public static final String FIND_BY_ID = "findById"; - public static final String FIND_BY_IDS = "findByIds"; - public static final String FIND_BY_EXAMPLE = "findByExample"; - public static final String CREATE_OBJECT = "createObject"; - public static final String PROCESS_TRANSACTION = "processTransaction"; - public static final String UPDATES_RECEIVED = "updatesReceived"; - public static final String DELETES_RECEIVED = "deletesReceived"; - public static final String PUT = "putObject"; - public static final String REMOVE = "removeObject"; - public static final String GET_ALL_BY_NAME = "getAllByName"; - public static final String RUN_QUERY = "runQuery"; - public static final String RUN_PROCESS = "runProcess"; - public static final String GET_ACCESSOR = "getAccessor"; - public static final String GET_HISTORY = "getHistory"; - public static final String GET_CHANGE_WATCHER = "getChangeWatcher"; - - private static Logger logger = Logger.getLogger("com.percero"); - - /** - * Message handling function - */ - @SuppressWarnings("unchecked") - @Transactional - public void onMessage(Message message) { - Object result = ""; - SyncRequest request = null; - SyncResponse response = null; - String key = ""; - try{ - if (!manifestProcessed) { - syncAgentService.processManifest(); - manifestProcessed = true; - } - - Object ob = decoder.decode(message.getBody()); - if (ob instanceof SyncRequest) - request = (SyncRequest) ob; - - key = message.getMessageProperties().getReceivedRoutingKey(); - - logger.debug("Received message " + key); - - if(CONNECT.equals(key)){ - if (request instanceof ConnectRequest) { - // Need to check for existing client here, before authenticateOAuth because authenticateOAuth will create - // the UserDevice client record if it does not exist. - ConnectRequest connectRequest = (ConnectRequest) request; - Set existingClientIds = accessManager.findClientByUserIdDeviceId(connectRequest.getUserId(), connectRequest.getDeviceId()); - Principal pUser = accountHelper.authenticateOAuth(connectRequest.getRegAppKey(), connectRequest.getSvcOauthKey(), connectRequest.getUserId(), connectRequest.getToken(), connectRequest.getClientId(), connectRequest.getClientType(), connectRequest.getDeviceId()); - ConnectResponse connectResponse = new ConnectResponse(); - connectResponse.setCurrentTimestamp( (new Date()).getTime() ); - - if (pUser != null) { - final Collection updateJournals = accessManager.getClientUpdateJournals(connectRequest.getClientId(), true); - final Collection deleteJournals = accessManager.getClientDeleteJournals(connectRequest.getClientId(), true); - - // The client will only have UpdateJournals and DeleteJournals if the UserDevice exists. - accessManager.registerClient(connectRequest.getClientId(), connectRequest.getUserId(), connectRequest.getDeviceId()); - connectResponse.setClientId(connectRequest.getClientId()); - connectResponse.setDataID(syncAgentService.getDataId(connectRequest.getClientId())); - - // Check to see if UserDevice exists. - if (existingClientIds != null && !existingClientIds.isEmpty()) { - Iterator itrExistingClientIds = existingClientIds.iterator(); - while (itrExistingClientIds.hasNext()) { - String nextExistingClientId = itrExistingClientIds.next(); - connectResponse.setData(nextExistingClientId); - - // Push all UpdateJournals for this Client. - updateJournals.addAll( accessManager.getClientUpdateJournals(nextExistingClientId, true) ); - //pushSyncHelper.pushUpdateJournals(updateJournals); - - // Push all DeleteJournals for this Client. - deleteJournals.addAll( accessManager.getClientDeleteJournals(nextExistingClientId, true) ); - //pushSyncHelper.pushDeleteJournals(deleteJournals); - } - } - else { - connectResponse.setData(null); - } - - syncAgentService.pushClientUpdateJournals(connectRequest.getClientId(), updateJournals); - syncAgentService.pushClientDeleteJournals(connectRequest.getClientId(), deleteJournals); - } else { - logger.warn("Unable to get valid Principal User"); - } - - response = connectResponse; - } - } - else if(HIBERNATE.equals(key)){ - if (request instanceof HibernateRequest) { - HibernateRequest hibernateRequest = (HibernateRequest) request; - HibernateResponse hibernateResponse = new HibernateResponse(); - hibernateResponse.setResult(accessManager.hibernateClient(hibernateRequest.getClientId(), hibernateRequest.getUserId())); - response = hibernateResponse; - //amqpAdmin.purgeQueue(hibernateRequest.getClientId(), true); - //boolean deleteResult = amqpAdmin.deleteQueue(hibernateRequest.getClientId()); - //System.out.println("Deleted Queue " + hibernateRequest.getClientId() + ": " + deleteResult); - } - } - else if(UPGRADE_CLIENT.equals(key)){ - if (request instanceof UpgradeClientRequest) { - UpgradeClientRequest upgradeClientRequest = (UpgradeClientRequest) request; - UpgradeClientResponse upgradeClientResponse = new UpgradeClientResponse(); - upgradeClientResponse.setResult(accessManager.upgradeClient(upgradeClientRequest.getClientId(), upgradeClientRequest.getDeviceId(), upgradeClientRequest.getDeviceType(), upgradeClientRequest.getUserId())); - response = upgradeClientResponse; - - if (upgradeClientResponse.getResult()) { - // If upgrade successful, then check for existing updates and push to client. - accessManager.registerClient(upgradeClientRequest.getClientId(), upgradeClientRequest.getUserId(), upgradeClientRequest.getDeviceId()); - upgradeClientResponse.setClientId(upgradeClientRequest.getClientId()); - - // Push all UpdateJournals for this Client. - final Collection updateJournals = accessManager.getClientUpdateJournals(upgradeClientRequest.getClientId(), true); - //pushSyncHelper.pushUpdateJournals(updateJournals); - syncAgentService.pushClientUpdateJournals(upgradeClientRequest.getClientId(), updateJournals); - - // Push all DeleteJournals for this Client. - final Collection deleteJournals = accessManager.getClientDeleteJournals(upgradeClientRequest.getClientId(), true); - //pushSyncHelper.pushDeleteJournals(deleteJournals); - syncAgentService.pushClientDeleteJournals(upgradeClientRequest.getClientId(), deleteJournals); - } - else - { - logger.warn("Unable to upgrade client"); - } - } - } - else if(DISCONNECT.equals(key)){ - if (request instanceof DisconnectRequest) { - DisconnectRequest disconnectRequest = (DisconnectRequest) request; - if (accessManager.isNonPersistentClient(disconnectRequest.getClientId())) { - // Need to delete the queue that this client is connected to since it is a non-persistent client. - MessageProperties mp = message.getMessageProperties(); - //amqpAdmin.deleteQueue(mp.getReplyTo()); - } - else { - logger.debug("Leaving MessageQueue intact since client is NOT a non-persistent client."); - } - accessManager.logoutClient(disconnectRequest.getClientId(), false); - response = null; - } - } - else if(LOGOUT.equals(key)){ - if (request instanceof LogoutRequest) { - LogoutRequest logoutRequest = (LogoutRequest) request; - if (accessManager.isNonPersistentClient(logoutRequest.getClientId())) { - // Need to delete the queue that this client is connected to since it is a non-persistent client. - MessageProperties mp = message.getMessageProperties(); - //amqpAdmin.deleteQueue(mp.getReplyTo()); - } - else { - logger.debug("Leaving MessageQueue intact since client is NOT a non-persistent client."); - } - accessManager.logoutClient(logoutRequest.getClientId(), logoutRequest.getPleaseDestroyClient()); - response = null; - } - } - else if(FIND_BY_IDS.equals(key)){ - if (request instanceof FindByIdsRequest) { - FindByIdsRequest findByIdsRequest = (FindByIdsRequest) request; - result = syncAgentService.findByIds(findByIdsRequest.getTheClassIdList(), findByIdsRequest.getClientId()); - response = new FindByIdsResponse(); - ((FindByIdsResponse)response).setResult((List)result); - } - } - else if(FIND_BY_ID.equals(key)){ - if (request instanceof FindByIdRequest) { - FindByIdRequest findByIdRequest = (FindByIdRequest) request; - result = syncAgentService.findById(findByIdRequest.getTheClassName(), findByIdRequest.getTheClassId(), findByIdRequest.getClientId()); - response = new FindByIdResponse(); - ((FindByIdResponse)response).setResult((BaseDataObject)result); - } - } - else if(FIND_BY_EXAMPLE.equals(key)){ - if (request instanceof FindByExampleRequest) { - FindByExampleRequest findByExampleRequest = (FindByExampleRequest) request; - result = syncAgentService.findByExample(findByExampleRequest.getTheObject(), null, findByExampleRequest.getClientId()); - response = new FindByExampleResponse(); - ((FindByExampleResponse)response).setResult((List)result); - } - } - else if(CREATE_OBJECT.equals(key)){ - if (request instanceof CreateRequest) { - CreateRequest createRequest = (CreateRequest) request; - ServerResponse createServerResponse = syncAgentService.createObject((IPerceroObject) createRequest.getTheObject(), createRequest.getClientId()); - response = new CreateResponse(); - ((CreateResponse)response).setResult(createServerResponse.getIsSuccessful()); - ((CreateResponse)response).setTheObject((BaseDataObject) createServerResponse.getResultObject()); - } - } - else if(PROCESS_TRANSACTION.equals(key)){ - if (request instanceof TransactionRequest) { - TransactionRequest processTransactionRequest = (TransactionRequest) request; - List objectsToSave = new ArrayList(); - objectsToSave.addAll(processTransactionRequest.getObjectsToSave()); - List objectsToRemove = new ArrayList(); - objectsToRemove.addAll(processTransactionRequest.getObjectsToRemove()); - - if (processTransactionRequest.getTransTimestamp() == null || processTransactionRequest.getTransTimestamp() <= 0) - processTransactionRequest.setTransTimestamp((new Date()).getTime()); - - ServerResponse processTransServerResponse = syncAgentService.processTransaction(objectsToSave, objectsToRemove, processTransactionRequest.getTransactionId(), new Date(processTransactionRequest.getTransTimestamp()), processTransactionRequest.getClientId()); - response = new TransactionResponse(); - ((TransactionResponse)response).setTransactionId(processTransactionRequest.getTransactionId()); - ((TransactionResponse)response).setResult(processTransServerResponse.getIsSuccessful()); - - // Add lists of saved and removed objects. - // If Transaction failed, then this provides a list of objects to rollback. - ((TransactionResponse)response).setObjectsSaved(new ArrayList()); - for(IPerceroObject nextSavedBDO : processTransactionRequest.getObjectsToSave()) { - ClassIDPair nextSavePair = new ClassIDPair(nextSavedBDO.getID(), nextSavedBDO.getClass().getName()); - ((TransactionResponse)response).getObjectsSaved().add(nextSavePair); - } - - ((TransactionResponse)response).setObjectsRemoved(new ArrayList()); - for(IPerceroObject nextRemovedBDO : processTransactionRequest.getObjectsToRemove()) { - ClassIDPair nextRemovePair = new ClassIDPair(nextRemovedBDO.getID(), nextRemovedBDO.getClass().getName()); - ((TransactionResponse)response).getObjectsRemoved().add(nextRemovePair); - } - } - } - else if(UPDATES_RECEIVED.equals(key)){ - if (request instanceof PushUpdatesReceivedRequest) { - PushUpdatesReceivedRequest pushUpdatesReceivedRequest = (PushUpdatesReceivedRequest) request; - syncAgentService.updatesReceived(pushUpdatesReceivedRequest.getClassIdPairs(), pushUpdatesReceivedRequest.getClientId()); - response = new PushUpdatesReceivedResponse(); - ((PushUpdatesReceivedResponse)response).setResult(true); - } - } - else if(DELETES_RECEIVED.equals(key)){ - if (request instanceof PushDeletesReceivedRequest) { - PushDeletesReceivedRequest pushDeletesReceivedRequest = (PushDeletesReceivedRequest) request; - syncAgentService.deletesReceived(pushDeletesReceivedRequest.getClassIdPairs(), pushDeletesReceivedRequest.getClientId()); - response = new PushDeletesReceivedResponse(); - ((PushDeletesReceivedResponse)response).setResult(true); - } - } - else if(PUT.equals(key)){ - if (request instanceof PutRequest) { - PutRequest putRequest = (PutRequest) request; - - - if (putRequest.getPutTimestamp() == null || putRequest.getPutTimestamp() <= 0) - putRequest.setPutTimestamp((new Date()).getTime()); - ServerResponse putServerResponse = syncAgentService.putObject((IPerceroObject) putRequest.getTheObject(), putRequest.getTransId(), new Date(putRequest.getPutTimestamp()), putRequest.getClientId()); - response = new PutResponse(); - ((PutResponse)response).setResult(putServerResponse.getIsSuccessful()); - //((PutResponse)response).setResult(false); - } - } - else if(REMOVE.equals(key)){ - if (request instanceof RemoveRequest) { - RemoveRequest removeRequest = (RemoveRequest) request; - ServerResponse removeServerResponse = syncAgentService.deleteObject(removeRequest.getRemovePair(), removeRequest.getClientId()); - response = new RemoveResponse(); - ((RemoveResponse)response).setResult(removeServerResponse.getIsSuccessful()); - } - } - else if(key.equals("findUnique")){ - // TODO: result = syncAgentService.findUnique(ob, userId); - } - else if(GET_ALL_BY_NAME.equals(key)){ - if (request instanceof GetAllByNameRequest) { - GetAllByNameRequest getAllByNameRequest = (GetAllByNameRequest) request; - result = syncAgentService.getAllByName(getAllByNameRequest.getTheClassName(), getAllByNameRequest.getPageNumber(), getAllByNameRequest.getPageSize(), getAllByNameRequest.getReturnTotal(), getAllByNameRequest.getClientId()); - response = new GetAllByNameResponse(); - ((GetAllByNameResponse)response).setResult((List)result); - ((GetAllByNameResponse)response).setPageNumber(getAllByNameRequest.getPageNumber()); - ((GetAllByNameResponse)response).setPageSize(getAllByNameRequest.getPageSize()); - } - } - else if(RUN_QUERY.equals(key)){ - if (request instanceof RunQueryRequest) { - RunQueryRequest runQueryRequest = (RunQueryRequest) request; - result = syncAgentService.runQuery(runQueryRequest.getTheClassName(), runQueryRequest.getQueryName(), runQueryRequest.getQueryArguments(), runQueryRequest.getClientId()); - response = new RunQueryResponse(); - ((RunQueryResponse)response).setResult((List)result); - } - } - else if(GET_CHANGE_WATCHER.equals(key)){ - if (request instanceof PushCWUpdateRequest) { - PushCWUpdateRequest pushCwUpdateRequest = (PushCWUpdateRequest) request; - result = syncAgentService.getChangeWatcher(pushCwUpdateRequest.getClassIdPair(), pushCwUpdateRequest.getFieldName(), pushCwUpdateRequest.getParams(), pushCwUpdateRequest.getClientId()); - response = new PushCWUpdateResponse(); - ((PushCWUpdateResponse)response).setFieldName(pushCwUpdateRequest.getFieldName()); - ((PushCWUpdateResponse)response).setParams(pushCwUpdateRequest.getParams()); - ((PushCWUpdateResponse)response).setClassIdPair(pushCwUpdateRequest.getClassIdPair()); - ((PushCWUpdateResponse)response).setValue(result); - } - } - else if(RUN_PROCESS.equals(key)){ - if (request instanceof RunProcessRequest) { - RunProcessRequest runProcessRequest = (RunProcessRequest) request; - result = syncAgentService.runProcess(runProcessRequest.getQueryName(), runProcessRequest.getQueryArguments(), runProcessRequest.getClientId()); - response = new RunProcessResponse(); - ((RunProcessResponse)response).setResult(result); - } - } - else if(GET_ACCESSOR.equals(key)){ - if (request instanceof GetAccessorRequest) { - GetAccessorRequest getAccessorRequest = (GetAccessorRequest) request; - IAccessor accessor = accessorService.getAccessor(getAccessorRequest.getUserId(), getAccessorRequest.getTheClassName(), getAccessorRequest.getTheClassId()); - result = accessor; - response = new GetAccessorResponse(); - ((GetAccessorResponse)response).setAccessor(accessor); - - if (accessor != null && accessor.getCanRead() && getAccessorRequest.getReturnObject()) { - // User has access and has requested that the object be returned. - Object foundObject = syncAgentService.findById(getAccessorRequest.getTheClassName(), getAccessorRequest.getTheClassId(), getAccessorRequest.getClientId()); - - if (foundObject instanceof BaseDataObject) { - ((GetAccessorResponse)response).setResultObject((BaseDataObject)foundObject); - } - } - } - } - else if(GET_HISTORY.equals(key)){ - if (request instanceof GetHistoryRequest) { - GetHistoryRequest getHistoryRequest = (GetHistoryRequest) request; - result = syncAgentService.getHistory(getHistoryRequest.getTheClassName(), getHistoryRequest.getTheClassId(), getHistoryRequest.getClientId()); - response = new GetHistoryResponse(); - ((GetHistoryResponse)response).setResult((List)result); - } - } - else if(key.equals("searchByExample")) { - // TODO: result = syncAgentService.searchByExample(ob, userId); - } - else { - System.out.println("Unknown Message Type"); - } - } catch(SyncException e) { - logger.error(e.getCode().toString() + ": " + e.getName(), e); - - response = new SyncErrorResponse(); - ((SyncErrorResponse) response).setErrorName(e.getName()); - ((SyncErrorResponse) response).setErrorCode(e.getCode()); - ((SyncErrorResponse) response).setErrorDesc(e.getMessage()); - } catch(Exception e) { - logger.error(e.getMessage(), e); - - response = new SyncErrorResponse(); - ((SyncErrorResponse) response).setErrorName(e.getMessage()); - ((SyncErrorResponse) response).setErrorCode(0); - ((SyncErrorResponse) response).setErrorDesc(e.getMessage()); - } finally { - // Send a message back to the originator - try { - if (message.getMessageProperties().getReplyTo() != null && !message.getMessageProperties().getReplyTo().isEmpty()) { - if (request != null) - { - if (response == null) - response = new SyncResponse(); - response.setClientId(request.getClientId()); - response.setCorrespondingMessageId(request.getMessageId()); - if (response.getData() == null) - response.setData(result); - - if (response instanceof GetHistoryResponse) { - template.convertAndSend(message.getMessageProperties().getReplyTo(), response); - } - else { - pushSyncHelper.pushSyncResponseToClient(response, message.getMessageProperties().getReplyTo()); - //String json = response.toJson(safeObjectMapper); - //pushSyncHelper.pushJsonToRouting(json, response.getClass(), message.getMessageProperties().getReplyTo()); - /*String jsonString = jsonObjectMapper.writeValueAsString(response); - if (jsonString.compareTo(json) != 0) - { - System.out.println("JSON_NEW:" + json); - System.out.println("JSON_OLD:" + jsonString); - SyncResponse object_New = (SyncResponse) decoder.decode(json.getBytes()); - SyncResponse object_Old = (SyncResponse) decoder.decode(json.getBytes()); - System.out.println("Are Equal: " + com.mchange.v2.lang.ObjectUtils.eqOrBothNull(object_New, object_Old)); - }*/ - //template.convertAndSend(message.getMessageProperties().getReplyTo(), response); - } - } - else - template.convertAndSend(message.getMessageProperties().getReplyTo(), result); - - logger.debug("Finished message " + key); - } - } - catch(Exception e){ - logger.error(e.getMessage(), e); - } - } - } -} diff --git a/src/main/java/com/percero/amqp/handlers/GetChangeWatcherHandler.java b/src/main/java/com/percero/amqp/handlers/GetChangeWatcherHandler.java index 87651f9..e2020fe 100644 --- a/src/main/java/com/percero/amqp/handlers/GetChangeWatcherHandler.java +++ b/src/main/java/com/percero/amqp/handlers/GetChangeWatcherHandler.java @@ -20,7 +20,7 @@ public GetChangeWatcherHandler() { public SyncResponse handleMessage(SyncRequest request, String replyTo) throws Exception { PushCWUpdateResponse response = new PushCWUpdateResponse(); PushCWUpdateRequest pushCwUpdateRequest = (PushCWUpdateRequest) request; - Object result = syncAgentService.getChangeWatcher(pushCwUpdateRequest.getClassIdPair(), pushCwUpdateRequest.getFieldName(), pushCwUpdateRequest.getParams(), pushCwUpdateRequest.getClientId()); + Object result = syncAgentService.getChangeWatcherValue(pushCwUpdateRequest.getClassIdPair(), pushCwUpdateRequest.getFieldName(), pushCwUpdateRequest.getParams(), pushCwUpdateRequest.getClientId()); response.setFieldName(pushCwUpdateRequest.getFieldName()); response.setParams(pushCwUpdateRequest.getParams()); response.setClassIdPair(pushCwUpdateRequest.getClassIdPair()); diff --git a/src/main/java/com/percero/util/RandomStringGenerator.java b/src/main/java/com/percero/util/RandomStringGenerator.java new file mode 100644 index 0000000..1a0913d --- /dev/null +++ b/src/main/java/com/percero/util/RandomStringGenerator.java @@ -0,0 +1,44 @@ +package com.percero.util; + +/** + * Credit to: http://syntx.io/how-to-generate-a-random-string-in-java/ + */ +public class RandomStringGenerator { + + public static enum Mode { + ALPHA, ALPHANUMERIC, NUMERIC + } + + public static String string(int length) { + return string(length, Mode.ALPHANUMERIC); + } + + public static String string(int length, Mode mode) { + + StringBuffer buffer = new StringBuffer(); + String characters = ""; + + switch(mode){ + + case ALPHA: + characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + break; + + case ALPHANUMERIC: + characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + break; + + case NUMERIC: + characters = "1234567890"; + break; + } + + int charactersLength = characters.length(); + + for (int i = 0; i < length; i++) { + double index = Math.random() * charactersLength; + buffer.append(characters.charAt((int) index)); + } + return buffer.toString(); + } +} \ No newline at end of file diff --git a/src/main/resources/spring/percero-spring-config.xml b/src/main/resources/spring/percero-spring-config.xml index 4e7c47a..a7f0cff 100644 --- a/src/main/resources/spring/percero-spring-config.xml +++ b/src/main/resources/spring/percero-spring-config.xml @@ -104,6 +104,8 @@ message-converter="jsonConverter" /> + + @@ -147,7 +149,7 @@ diff --git a/src/test/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStoreTest.java b/src/test/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStoreTest.java new file mode 100644 index 0000000..8e9834a --- /dev/null +++ b/src/test/java/com/percero/agents/sync/datastore/RedisClusterCacheDataStoreTest.java @@ -0,0 +1,142 @@ +package com.percero.agents.sync.datastore; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.ListOperations; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.SetOperations; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.data.redis.core.ZSetOperations; + +import com.percero.agents.sync.services.PerceroRedisTemplate; + +@RunWith(MockitoJUnitRunner.class) +public class RedisClusterCacheDataStoreTest { + + @Mock + private PerceroRedisTemplate template; + + @InjectMocks + private RedisClusterCacheDataStore redisCacheDataStore; + + @Mock + private SetOperations setOperations; + + @Mock + private ListOperations listOperations; + + @Mock + private HashOperations hashOperations; + + @Mock + private ValueOperations valueOperations; + + @Mock + private ZSetOperations zsetOperations; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { +// redisCacheDataStore = new RedisCacheDataStore(); + + Mockito.when(template.opsForSet()).thenReturn(setOperations); + Mockito.when(template.opsForList()).thenReturn(listOperations); + Mockito.when(template.opsForHash()).thenReturn(hashOperations); + Mockito.when(template.opsForValue()).thenReturn(valueOperations); + Mockito.when(template.opsForZSet()).thenReturn(zsetOperations); + } + + @SuppressWarnings("unchecked") + @After + public void tearDown() throws Exception { + // Confirm that no non-cluster safe operations have been performed. + + // Sets + Mockito.verify(setOperations, Mockito.never()).union(Mockito.anyString(), Mockito.anyCollection()); + Mockito.verify(setOperations, Mockito.never()).union(Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).unionAndStore(Mockito.anyString(), Mockito.anyCollection(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).unionAndStore(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).difference(Mockito.anyString(), Mockito.anyCollection()); + Mockito.verify(setOperations, Mockito.never()).difference(Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).differenceAndStore(Mockito.anyString(), Mockito.anyCollection(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).differenceAndStore(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).intersect(Mockito.anyString(), Mockito.anyCollection()); + Mockito.verify(setOperations, Mockito.never()).intersect(Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).intersectAndStore(Mockito.anyString(), Mockito.anyCollection(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).intersectAndStore(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).move(Mockito.anyString(), Mockito.anyObject(), Mockito.anyString()); + Mockito.verify(setOperations, Mockito.never()).scan(Mockito.anyString(), Mockito.any(ScanOptions.class)); + + // ZSets + Mockito.verify(zsetOperations, Mockito.never()).unionAndStore(Mockito.anyString(), Mockito.anyCollection(), Mockito.anyString()); + Mockito.verify(zsetOperations, Mockito.never()).unionAndStore(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + Mockito.verify(zsetOperations, Mockito.never()).intersectAndStore(Mockito.anyString(), Mockito.anyCollection(), Mockito.anyString()); + Mockito.verify(zsetOperations, Mockito.never()).intersectAndStore(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()); + Mockito.verify(zsetOperations, Mockito.never()).scan(Mockito.anyString(), Mockito.any(ScanOptions.class)); + + // Hashes + Mockito.verify(hashOperations, Mockito.never()).scan(Mockito.anyString(), Mockito.any(ScanOptions.class)); + + // Value + Mockito.verify(valueOperations, Mockito.never()).multiGet(Mockito.anyCollection()); + + } + + @Test + public void testExpire() { + String key = "KEY"; + long timeout = 1000; + TimeUnit timeUnit = TimeUnit.MILLISECONDS; + + redisCacheDataStore.expire(key, timeout, timeUnit); + Mockito.verify(template, Mockito.never()).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + redisCacheDataStore.expire(key, timeout, timeUnit, false); + Mockito.verify(template, Mockito.never()).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + Collection keys = new ArrayList(); + keys.add("KEY_1"); + keys.add("KEY_2"); + + redisCacheDataStore.expire(keys, timeout, timeUnit); + Mockito.verify(template, Mockito.never()).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + redisCacheDataStore.expire(keys, timeout, timeUnit, false); + Mockito.verify(template, Mockito.never()).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + + redisCacheDataStore.expire(key, timeout, timeUnit, true); + Mockito.verify(template, Mockito.times(1)).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + // Test exit from expire loop. + Mockito.when(template.expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class))).thenReturn(false); + redisCacheDataStore.expire(keys, timeout, timeUnit, true); + Mockito.verify(template, Mockito.times(2)).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + + // Test complete expire loop + Mockito.when(template.expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class))).thenReturn(true); + redisCacheDataStore.expire(keys, timeout, timeUnit, true); + Mockito.verify(template, Mockito.times(4)).expire(Mockito.anyString(), Mockito.anyLong(), Mockito.any(TimeUnit.class)); + } + +}