This is an automated email from the git hooks/post-receive script. New commit to branch feature/7457 in repository observe. See http://git.codelutin.com/observe.git commit c486c3363928faef5cc1aaba1d48de7553204ed7 Author: Tony CHEMIT <chemit@codelutin.com> Date: Mon Aug 17 09:10:45 2015 +0200 Début de mise en place des services --- .../services/ObserveServiceFactorySupport.java | 55 ++++++++ .../services/ObserveServiceFactoryRest.java | 26 ++-- .../services/ObserveServiceContextTopia.java | 23 ++++ .../services/ObserveServiceFactoryTopia.java | 148 +++++++++++++++++++-- .../ird/observe/services/ObserveServiceTopia.java | 9 +- 5 files changed, 239 insertions(+), 22 deletions(-) diff --git a/observe-services-api/src/main/java/fr/ird/observe/services/ObserveServiceFactorySupport.java b/observe-services-api/src/main/java/fr/ird/observe/services/ObserveServiceFactorySupport.java new file mode 100644 index 0000000..22177a6 --- /dev/null +++ b/observe-services-api/src/main/java/fr/ird/observe/services/ObserveServiceFactorySupport.java @@ -0,0 +1,55 @@ +package fr.ird.observe.services; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +import java.util.concurrent.ExecutionException; + +/** + * Created on 16/08/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public abstract class ObserveServiceFactorySupport implements ObserveServiceFactory { + + protected <S extends ObserveService> Class<S> getServiceClassType(LoadingCache<Class<?>, Class<?>> serviceTypeCache, Class<S> serviceType) { + try { + return (Class<S>) serviceTypeCache.get(serviceType); + } catch (ExecutionException e) { + throw new IllegalStateException("Could not get class", e); + } + } + + protected <S extends ObserveService> S newServiceInstance(Class<S> serviceTypeImpl, ObserveServiceContext serviceContext) { + try { + S service = serviceTypeImpl.newInstance(); + service.setServiceContext(serviceContext); + return service; + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException("Could not create service", e); + } + } + + protected LoadingCache<Class<?>, Class<?>> newClassCache(final String suffix) { + + return CacheBuilder.newBuilder().build(new CacheLoader<Class<?>, Class<?>>() { + + @Override + public Class<?> load(Class<?> key) throws Exception { + + String fqn = key.getName() + suffix; + try { + Class<?> classImpl = Class.forName(fqn); + return classImpl; + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Could not get class: " + fqn, e); + } + + + } + }); + + } + +} diff --git a/observe-services-rest/src/main/java/fr/ird/observe/services/ObserveServiceFactoryRest.java b/observe-services-rest/src/main/java/fr/ird/observe/services/ObserveServiceFactoryRest.java index da7fcc5..7aac91f 100644 --- a/observe-services-rest/src/main/java/fr/ird/observe/services/ObserveServiceFactoryRest.java +++ b/observe-services-rest/src/main/java/fr/ird/observe/services/ObserveServiceFactoryRest.java @@ -1,27 +1,33 @@ package fr.ird.observe.services; +import com.google.common.base.Preconditions; +import com.google.common.cache.LoadingCache; + /** * Created on 16/08/15. * * @author Tony Chemit - chemit@codelutin.com */ -public class ObserveServiceFactoryRest implements ObserveServiceFactory { +public class ObserveServiceFactoryRest extends ObserveServiceFactorySupport { + + protected final LoadingCache<Class<?>, Class<?>> serviceTypeCache = newClassCache("Rest"); @Override public <S extends ObserveService> boolean accept(ObserveServiceContext serviceContext, Class<S> serviceType) { - return serviceContext != null && serviceType != null; + return serviceContext != null && serviceContext instanceof ObserveServiceContextRest && serviceType != null; } @Override public <S extends ObserveService> S newService(ObserveServiceContext serviceContext, Class<S> serviceType) { - String fqn = serviceType.getName() + "Rest"; - try { - S service = (S) Class.forName(fqn).newInstance(); - service.setServiceContext(serviceContext); - return service; - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - throw new IllegalStateException("Could not create service", e); - } + Preconditions.checkNotNull(serviceContext, "serviceContext can't be null."); + Preconditions.checkArgument(serviceContext instanceof ObserveServiceContextRest, "serviceContext must be of type " + ObserveServiceContextRest.class.getName()); + Preconditions.checkNotNull(serviceType, "serviceType can't be null."); + + Class<S> serviceTypeImpl = getServiceClassType(serviceTypeCache, serviceType); + S service = newServiceInstance(serviceTypeImpl, serviceContext); + return service; + } + } diff --git a/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceContextTopia.java b/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceContextTopia.java index af08ad3..474607e 100644 --- a/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceContextTopia.java +++ b/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceContextTopia.java @@ -1,5 +1,8 @@ package fr.ird.observe.services; +import fr.ird.observe.db.DataSource; +import org.nuiton.topia.TopiaContext; + /** * Created on 16/08/15. * @@ -7,4 +10,24 @@ package fr.ird.observe.services; */ public class ObserveServiceContextTopia implements ObserveServiceContext { + protected DataSource dataSource; + + protected TopiaContext transaction; + + public DataSource getDataSource() { + return dataSource; + } + + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + } + + public TopiaContext getTransaction() { + return transaction; + } + + public void setTransaction(TopiaContext transaction) { + this.transaction = transaction; + } + } diff --git a/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceFactoryTopia.java b/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceFactoryTopia.java index dcf5478..52e9885 100644 --- a/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceFactoryTopia.java +++ b/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceFactoryTopia.java @@ -1,27 +1,157 @@ package fr.ird.observe.services; +import com.google.common.base.Preconditions; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableSet; +import fr.ird.observe.db.DataSource; +import fr.ird.observe.services.spi.NoDataAccess; +import fr.ird.observe.services.spi.Write; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.topia.TopiaContext; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Set; + /** * Created on 16/08/15. * * @author Tony Chemit - chemit@codelutin.com */ -public class ObserveServiceFactoryTopia implements ObserveServiceFactory { +public class ObserveServiceFactoryTopia extends ObserveServiceFactorySupport { + + /** Logger. */ + private static final Log log = LogFactory.getLog(ObserveServiceFactoryTopia.class); + + protected final LoadingCache<Class<?>, Class<?>> serviceTypeCache = newClassCache("Topia"); @Override public <S extends ObserveService> boolean accept(ObserveServiceContext serviceContext, Class<S> serviceType) { - return serviceContext != null && serviceType != null; + return serviceContext != null && serviceContext instanceof ObserveServiceContextTopia && serviceType != null; } @Override public <S extends ObserveService> S newService(ObserveServiceContext serviceContext, Class<S> serviceType) { - String fqn = serviceType.getName() + "Topia"; - try { - S service = (S) Class.forName(fqn).newInstance(); - service.setServiceContext(serviceContext); - return service; - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - throw new IllegalStateException("Could not create service", e); + Preconditions.checkNotNull(serviceContext, "serviceContext can't be null."); + Preconditions.checkArgument(serviceContext instanceof ObserveServiceContextTopia, "serviceContext must be of type " + ObserveServiceContextTopia.class.getName()); + Preconditions.checkNotNull(serviceType, "serviceType can't be null."); + + Class<S> serviceTypeImpl = getServiceClassType(serviceTypeCache, serviceType); + S service = newServiceInstance(serviceTypeImpl, serviceContext); + service = newServiceTransactionalProxy(serviceType, service, (ObserveServiceContextTopia) serviceContext); + return service; + + } + + protected <S extends ObserveService> S newServiceTransactionalProxy(Class<S> serviceType, S service, ObserveServiceContextTopia serviceContext) { + + ObserveServiceInvocationHandler invocationHandler = new ObserveServiceInvocationHandler(serviceContext, service); + Object proxyService = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{serviceType}, invocationHandler); + return (S) proxyService; + + } + + protected static class ObserveServiceInvocationHandler implements InvocationHandler { + + private final ObserveServiceContextTopia serviceContext; + + private final ObserveService target; + + private final Set<String> methodNamesToByPass; + + protected ObserveServiceInvocationHandler(ObserveServiceContextTopia serviceContext, ObserveService target) { + + this.serviceContext = serviceContext; + this.target = target; + this.methodNamesToByPass = ImmutableSet.of( + "equals", + "hashCode", + "finalize", + "toString", + "clone", + "getClass", + "close"); + + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + Object result; + + if (serviceContext.getDataSource() == null /* FIXME Supprimer ce test dès qu'on aura une ds dans le context */ + || methodNamesToByPass.contains(method.getName()) + || method.isAnnotationPresent(NoDataAccess.class)) { + + result = invokeMethod(method, args); + + } else { + + result = invokeMethodWithTransaction(method, args); + + } + + return result; + + } + + protected Object invokeMethod(Method method, Object... args) throws Throwable { + try { + Object result = method.invoke(target, args); + return result; + } catch (InvocationTargetException e) { + if (log.isErrorEnabled()) { + log.error("Error in method " + method.getName(), e); + } + throw e.getCause(); + } + } + + protected Object invokeMethodWithTransaction(Method method, Object... args) throws Throwable { + + String methodName = method.getName(); + + DataSource source = serviceContext.getDataSource(); + + TopiaContext tx = source.beginTransaction(methodName); + + try { + + serviceContext.setTransaction(tx); + + Object invoke = invokeMethod(method, args); + + if (method.isAnnotationPresent(Write.class)) { + + // do commit + source.commitTransaction(tx, methodName); + + } + + return invoke; + + } finally { + + try { + + // always rollback transaction to avoid dirty transactions + source.rollbackTransaction(tx, methodName); + + } finally { + + serviceContext.setTransaction(null); + source.closeTransaction(tx, methodName); + + } + + } + } + } + } diff --git a/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceTopia.java b/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceTopia.java index 3431515..2b22014 100644 --- a/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceTopia.java +++ b/observe-services-topia/src/main/java/fr/ird/observe/services/ObserveServiceTopia.java @@ -1,5 +1,7 @@ package fr.ird.observe.services; +import com.google.common.base.Preconditions; + /** * Created on 16/08/15. * @@ -7,11 +9,12 @@ package fr.ird.observe.services; */ public class ObserveServiceTopia implements ObserveService { - protected ObserveServiceContext serviceContext; + protected ObserveServiceContextTopia serviceContext; @Override public void setServiceContext(ObserveServiceContext serviceContext) { - - this.serviceContext = serviceContext; + Preconditions.checkNotNull(serviceContext, "serviceContext can't be null."); + Preconditions.checkArgument(serviceContext instanceof ObserveServiceContextTopia, "serviceContext must be of type " + ObserveServiceContextTopia.class.getName()); + this.serviceContext = (ObserveServiceContextTopia) serviceContext; } } -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@list.forge.codelutin.com>.