/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs.module.sync.advice;
import java.lang.reflect.Method;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.GlobalProperty;
import org.openmrs.User;
import org.openmrs.api.AdministrationService;
import org.openmrs.api.UserService;
import org.openmrs.api.context.Context;
import org.openmrs.module.sync.SyncConstants;
import org.openmrs.module.sync.api.SyncService;
import org.openmrs.patient.impl.LuhnIdentifierValidator;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.util.StringUtils;
/**
* This class wraps around every method in the {@link UserService} class. Only the generateSystemId
* class is singled out and the String returned from it has the the current sync system's
* user-defined name in it.
*/
public class GenerateSystemIdAdvisor extends StaticMethodMatcherPointcutAdvisor implements Advisor {
private static final long serialVersionUID = 38539204394323L;
private Log log = LogFactory.getLog(this.getClass());
/**
* Match only to the "generateSystemId method
*
* @see org.springframework.aop.MethodMatcher#matches(java.lang.reflect.Method, java.lang.Class)
*/
@SuppressWarnings("unchecked")
public boolean matches(Method method, Class targetClass) {
return method.getName().equals("generateSystemId");
}
@Override
public Advice getAdvice() {
return new GenerateSystemIdAdvice();
}
/**
* This class has the actual logic to insert the name into the system id
*/
private class GenerateSystemIdAdvice implements MethodInterceptor {
/**
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
AdministrationService adminService = Context.getAdministrationService();
String systemId;
GlobalProperty systemIdTemplateGP = adminService.getGlobalPropertyObject(SyncConstants.PROPERTY_SYSTEM_ID_TEMPLATE);
if (systemIdTemplateGP != null) {
systemId = systemIdTemplateGP.getPropertyValue();
}
else {
systemId = SyncConstants.PROPERTY_SYSTEM_ID_TEMPLATE_DEFAULT;
}
// user cleared the property (and hopefully knows what they're doing), so use the built-in openmrs generator
if (!StringUtils.hasLength(systemId))
return (String) invocation.proceed();
UserService userService = Context.getUserService();
SyncService syncService = Context.getService(SyncService.class);
LuhnIdentifierValidator liv = new LuhnIdentifierValidator();
boolean generateCheckdigit = false;
if (systemId.contains("{CHECKDIGIT}")) {
generateCheckdigit = true;
systemId = systemId.replaceAll("\\{CHECKDIGIT\\}", "");
}
String serverName = syncService.getServerName();
if (systemId.contains("{SYNCSERVERNAME}") && StringUtils.hasLength(serverName)) {
systemId = systemId.replaceAll("\\{SYNCSERVERNAME\\}", serverName);
}
if (systemId.contains("{SYNCSERVERUUID}")) {
systemId = systemId.replaceAll("\\{SYNCSERVERUUID\\}", syncService.getServerUuid());
}
systemId = systemId.replaceAll(" ", ""); // drop all spaces so that we can generate the checkdigit if needed
systemId = systemId.replaceAll("-", ""); // drop all hyphens so that we can generate the checkdigit if needed
if (systemId.contains("{NEXTUSERID}")) {
Integer offset = 0;
User user = new User(); // temporary user to do the duplicate checking with
String tempSystemId; // this is used in case we have to loop
do {
// mimic what dao.generateSystemId does
Integer numberOfUsers = userService.getAllUsers().size() + 1;
// generate and increment the system id if necessary
Integer generatedId = numberOfUsers + offset++;
// apply this to a diff var in case we have to loop
tempSystemId = systemId.replaceAll("\\{NEXTUSERID\\}", generatedId.toString());
if (generateCheckdigit) {
try {
tempSystemId = liv.getValidIdentifier(tempSystemId);
}
catch (Exception e) {
log.error("error getting check digit", e);
// just continue and keep trying other numbers
}
}
// loop until we find a system id that no one has
user.setSystemId(tempSystemId);
} while (userService.hasDuplicateUsername(user));
systemId = tempSystemId;
// set this to false so that a second checkdigit isn't generated
generateCheckdigit = false;
}
if (generateCheckdigit) {
try {
systemId = liv.getValidIdentifier(systemId);
}
catch (Exception e) {
log.error("error getting check digit", e);
// just continue on without the checkdigit
}
}
return systemId;
}
}
}