This is an automated email from the git hooks/post-receive script. New commit to branch feature/single-page-ui in repository coselmar. See http://git.codelutin.com/coselmar.git commit 425b1419bd14dab8acce69a42d26f8349ea28bee Author: Yannick Martel <yannick.martel@gmail.com> Date: Thu Oct 30 18:06:27 2014 +0100 prepare web application --- .../persistence/CoselmarPersistenceContext.java | 12 ++ .../i18n/coselmar-persistence_en_GB.properties | 0 coselmar-services/pom.xml | 61 +++++-- .../fr/ifremer/coselmar/beans/DocumentBean.java | 64 +++++++ .../ifremer/coselmar/converter/DateConverter.java | 32 ++++ .../coselmar/converter/JsonArrayConverter.java | 56 ++++++ .../ifremer/coselmar/converter/JsonConverter.java | 66 +++++++ .../fr/ifremer/coselmar/converter/JsonHelper.java | 89 +++++++++ .../services/CoselmarApplicationContext.java | 25 +++ .../services/CoselmarRestApplicationListener.java | 72 ++++++++ .../services/CoselmarRestRequestContext.java | 34 ++++ .../coselmar/services/CoselmarRestUtil.java | 33 ++++ .../ifremer/coselmar/services/CoselmarService.java | 9 + .../CoselmarServicesApplicationContext.java | 200 +++++++++++++++++++++ .../coselmar/services/CoselmarServicesContext.java | 36 ++++ .../services/CoselmarTechnicalException.java | 24 +++ .../services/CoselmarWebServiceSupport.java | 73 ++++++++ .../services/DefaultCoselmarServicesContext.java | 102 +++++++++++ .../services/config/CoselmarServicesConfig.java | 85 +++++++++ .../config/CoselmarServicesConfigOption.java | 85 +++++++++ .../services/filter/CoselmarRestRequestFilter.java | 110 ++++++++++++ .../filter/CoselmarTopiaTransactionFilter.java | 48 +++++ .../CoselmarRestRequestContextInjector.java | 29 +++ .../injector/CoselmarServicesInjector.java | 32 ++++ .../coselmar/services/v1/DocumentsWebService.java | 47 +++++ .../ifremer/coselmar/services/v1/ErrorAction.java | 23 +++ .../main/resources/coselmar-services.properties | 8 + .../src/main/resources/log4j.properties | 9 + coselmar-services/src/main/resources/mapping | 34 ++++ coselmar-services/src/main/webapp/WEB-INF/web.xml | 23 +++ pom.xml | 38 +++- 31 files changed, 1541 insertions(+), 18 deletions(-) diff --git a/coselmar-persistence/src/main/java/fr/ifremer/coselmar/persistence/CoselmarPersistenceContext.java b/coselmar-persistence/src/main/java/fr/ifremer/coselmar/persistence/CoselmarPersistenceContext.java new file mode 100644 index 0000000..77f8e61 --- /dev/null +++ b/coselmar-persistence/src/main/java/fr/ifremer/coselmar/persistence/CoselmarPersistenceContext.java @@ -0,0 +1,12 @@ +package fr.ifremer.coselmar.persistence; + +import org.nuiton.topia.persistence.TopiaPersistenceContext; +import org.nuiton.topia.persistence.support.TopiaHibernateSupport; + +/** + * @author ymartel <martel@codelutin.com> + */ +public interface CoselmarPersistenceContext extends TopiaPersistenceContext, CoselmarTopiaDaoSupplier { + + TopiaHibernateSupport getHibernateSupport(); +} diff --git a/coselmar-persistence/src/main/resources/i18n/coselmar-persistence_en_GB.properties b/coselmar-persistence/src/main/resources/i18n/coselmar-persistence_en_GB.properties new file mode 100644 index 0000000..e69de29 diff --git a/coselmar-services/pom.xml b/coselmar-services/pom.xml index 2922fcd..6dfe806 100644 --- a/coselmar-services/pom.xml +++ b/coselmar-services/pom.xml @@ -16,6 +16,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <name>Coselmar :: Services</name> <description>Coselmar services module</description> + <packaging>war</packaging> <dependencies> @@ -47,6 +48,27 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-jcl</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </dependency> <!-- Nuiton --> <dependency> @@ -65,33 +87,29 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <groupId>org.nuiton</groupId> <artifactId>nuiton-converter</artifactId> </dependency> + <dependency> + <groupId>org.nuiton.web</groupId> + <artifactId>nuiton-web</artifactId> + </dependency> - <!-- web exposition --> + <!-- web part --> <dependency> <groupId>org.debux.webmotion</groupId> <artifactId>webmotion</artifactId> </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + </dependency> <!-- Tests --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-jcl</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>log4j</groupId> - <artifactId>log4j</artifactId> - <scope>test</scope> - </dependency> </dependencies> - - <build> <testResources> @@ -110,13 +128,26 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> - <path>/chorem</path> + <path>/services</path> <uriEncoding>UTF-8</uriEncoding> <systemProperties> - <chorem.log.dir>${basedir}/target</chorem.log.dir> + <!--<coselmar.logConfigurationFile>${basedir}/target</coselmar.logConfigurationFile>--> </systemProperties> </configuration> </plugin> + + <plugin> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-maven-plugin</artifactId> + <configuration> + <stopKey>B</stopKey> + <stopPort>1270</stopPort> + <contextXml>${basedir}/src/jetty/jetty-context.xml</contextXml> + <webAppConfig> + <contextPath>/services</contextPath> + </webAppConfig> + </configuration> + </plugin> </plugins> </pluginManagement> diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/beans/DocumentBean.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/beans/DocumentBean.java new file mode 100644 index 0000000..d96652f --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/beans/DocumentBean.java @@ -0,0 +1,64 @@ +package fr.ifremer.coselmar.beans; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class DocumentBean implements Serializable { + + protected String id; + protected String name; + protected String ownerName; + protected String privacy; + protected Date depositDate; + + public DocumentBean(String id, String name, String ownerName, String privacy, Date depositDate) { + this.id = id; + this.name = name; + this.ownerName = ownerName; + this.privacy = privacy; + this.depositDate = depositDate; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getOwnerName() { + return ownerName; + } + + public void setOwnerName(String ownerName) { + this.ownerName = ownerName; + } + + public String getPrivacy() { + return privacy; + } + + public void setPrivacy(String privacy) { + this.privacy = privacy; + } + + public Date getDepositDate() { + return depositDate; + } + + public void setDepositDate(Date depositDate) { + this.depositDate = depositDate; + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/DateConverter.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/DateConverter.java new file mode 100644 index 0000000..9492c24 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/DateConverter.java @@ -0,0 +1,32 @@ +package fr.ifremer.coselmar.converter; + +import java.util.Date; + +import org.apache.commons.beanutils.converters.AbstractConverter; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class DateConverter extends AbstractConverter { + + @Override + protected <T> T convertToType(Class<T> type, Object value) throws Throwable { + Date result = null; + if (value != null) { + if (value.getClass().isAssignableFrom(Date.class)) { + result = (Date) value; + } else { + Object o = ((Object[]) value)[0]; + String sTime = o.toString(); + Long time = Long.parseLong(sTime); + result = new Date(time); + } + } + return (T) result; + } + + @Override + protected Class<?> getDefaultType() { + return Date.class; + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/JsonArrayConverter.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/JsonArrayConverter.java new file mode 100644 index 0000000..fa649cc --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/JsonArrayConverter.java @@ -0,0 +1,56 @@ +package fr.ifremer.coselmar.converter; + +import com.google.common.reflect.TypeParameter; +import com.google.common.reflect.TypeToken; +import org.apache.commons.beanutils.converters.AbstractConverter; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class JsonArrayConverter<O> extends AbstractConverter { + + protected final Class<O[]> arrayType; + + protected final JsonHelper jsonHelper; + + public static <O> JsonArrayConverter<O> newConverter(Class<O> objectType) { + return new JsonArrayConverter<>(objectType); + } + + public JsonArrayConverter(Class<O> entityType) { + + this.arrayType = (Class<O[]>) new TypeToken<O[]>() { + } + .where(new TypeParameter<O>() { + }, entityType) + .getType(); + this.jsonHelper = new JsonHelper(false); + } + + @Override + protected <T> T convertToType(Class<T> type, Object value) throws Throwable { + + String stringValue; + + if (value instanceof String) { + + stringValue = (String) value; + + } else { + + stringValue = ((String[]) value)[0]; + + } + + O[] values = jsonHelper.fromJson(stringValue, this.arrayType); + + return (T) values; + + } + + @Override + public Class<?> getDefaultType() { + return arrayType; + } +} + diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/JsonConverter.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/JsonConverter.java new file mode 100644 index 0000000..64a0c3f --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/JsonConverter.java @@ -0,0 +1,66 @@ +package fr.ifremer.coselmar.converter; + +import fr.ifremer.coselmar.persistence.CoselmarEntityEnum; +import org.apache.commons.beanutils.converters.AbstractConverter; +import org.nuiton.topia.persistence.TopiaEntity; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class JsonConverter<O> extends AbstractConverter { + + protected Class<O> objectType; + + protected Class<O> implementationClass; + + protected final JsonHelper jsonHelper; + + public static <O> JsonConverter<O> newConverter(Class<O> objectType) { + return newConverter(objectType, objectType); + } + + public static <E extends TopiaEntity> JsonConverter<E> newEntityConverter(Class<E> objectType) { + Class<E> implementationClass = CoselmarEntityEnum.getImplementationClass(objectType); + return newConverter(objectType, implementationClass); + } + + public static <O> JsonConverter<O> newConverter(Class<O> objectType, Class<O> implementationClass) { + return new JsonConverter<>(objectType, implementationClass); + } + + public JsonConverter(Class<O> objectType, Class<O> implementationClass) { + this.objectType = objectType; + this.jsonHelper = new JsonHelper(false); + this.implementationClass = implementationClass; + } + + @Override + protected String convertToString(Object value) throws Throwable { + + String result = jsonHelper.toJson(value); + return result; + } + + @Override + protected <T> T convertToType(Class<T> type, Object value) throws Throwable { + + String stringValue; + + if (value instanceof String) { + stringValue = (String) value; + + } else { + stringValue = ((String[]) value)[0]; + } + + T result = (T) jsonHelper.fromJson(stringValue, implementationClass); + + return result; + } + + @Override + protected Class<O> getDefaultType() { + return objectType; + } + +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/JsonHelper.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/JsonHelper.java new file mode 100644 index 0000000..f9b840a --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/converter/JsonHelper.java @@ -0,0 +1,89 @@ +package fr.ifremer.coselmar.converter; + +import java.lang.reflect.Type; +import java.util.Date; + +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +public class JsonHelper { + + private final Gson gson; + + public JsonHelper(boolean prettyPrint) { + + GsonBuilder gsonBuilder = new GsonBuilder(); + + gsonBuilder.setExclusionStrategies(new ExclusionStrategy() { + @Override + public boolean shouldSkipField(FieldAttributes f) { + return false; + } + + @Override + public boolean shouldSkipClass(Class<?> clazz) { + return clazz == Class.class; + } + }); + + gsonBuilder.registerTypeAdapter(Date.class, new JsonSerializer<Date>() { + + @Override + public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { + + JsonElement result; + + if (src == null) { + result = JsonNull.INSTANCE; + + } else { + result = new JsonPrimitive(src.getTime()); + } + + return result; + } + + }); + + gsonBuilder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() { + + @Override + public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + return new Date(json.getAsLong()); + } + + }); + + if (prettyPrint) { + gsonBuilder.setPrettyPrinting(); + } + + this.gson = gsonBuilder.create(); + } + + public String toJson(Object model) { + String json = gson.toJson(model); + return json; + } + + public <O> O fromJson(String json, Class<O> type) { + O o = gson.fromJson(json, type); + return o; + } + + public <O> O fromJson(String json, Type type) { + O o = gson.fromJson(json, type); + return o; + } + +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarApplicationContext.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarApplicationContext.java new file mode 100644 index 0000000..c12133d --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarApplicationContext.java @@ -0,0 +1,25 @@ +package fr.ifremer.coselmar.services; + +import java.io.Closeable; +import java.util.Locale; + +import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; +import fr.ifremer.coselmar.persistence.CoselmarTopiaApplicationContext; +import fr.ifremer.coselmar.persistence.CoselmarTopiaPersistenceContext; +import fr.ifremer.coselmar.services.config.CoselmarServicesConfig; + +/** + * @author ymartel <martel@codelutin.com> + */ +public interface CoselmarApplicationContext extends Closeable { + + CoselmarTopiaApplicationContext getTopiaApplicationContext(); + + CoselmarServicesConfig getApplicationConfig(); + + CoselmarTopiaPersistenceContext newPersistenceContext(); + + CoselmarServicesContext newServiceContext(CoselmarPersistenceContext persistenceContext, Locale locale); + + void init(); +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java new file mode 100644 index 0000000..74d0356 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java @@ -0,0 +1,72 @@ +package fr.ifremer.coselmar.services; + +import java.util.Date; +import java.util.Set; + +import com.google.common.collect.Sets; +import fr.ifremer.coselmar.beans.DocumentBean; +import fr.ifremer.coselmar.converter.DateConverter; +import fr.ifremer.coselmar.converter.JsonArrayConverter; +import fr.ifremer.coselmar.converter.JsonConverter; +import fr.ifremer.coselmar.services.injector.CoselmarRestRequestContextInjector; +import fr.ifremer.coselmar.services.injector.CoselmarServicesInjector; +import org.debux.webmotion.server.WebMotionServerListener; +import org.debux.webmotion.server.call.ServerContext; +import org.debux.webmotion.server.mapping.Mapping; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class CoselmarRestApplicationListener implements WebMotionServerListener { + + protected static final Set<Class<?>> BEAN_TYPES = Sets.<Class<?>>newHashSet( + DocumentBean.class + ); + + @Override + public void onStart(Mapping mapping, ServerContext serverContext) { + + // init application context // + System.out.println("start"); + + CoselmarServicesApplicationContext applicationContext = + CoselmarServicesApplicationContext.getApplicationContext(); + System.out.println("application context get"); + + CoselmarServicesApplicationContext.setApplicationContext(serverContext.getServletContext(), applicationContext); + + // init converters // + + serverContext.addConverter(new DateConverter(), Date.class); + + for (Class<?> beanType : BEAN_TYPES) { + + serverContext.addConverter(JsonConverter.newConverter(beanType), beanType); + + JsonArrayConverter<?> converter = JsonArrayConverter.newConverter(beanType); + serverContext.addConverter(converter, converter.getDefaultType()); + + } + + // init injectors // + + System.out.println("add injectors"); + serverContext.addInjector(new CoselmarRestRequestContextInjector()); + serverContext.addInjector(new CoselmarServicesInjector()); + + } + + @Override + public void onStop(ServerContext serverContext) { + + // Get application context + CoselmarServicesApplicationContext applicationContext = + CoselmarServicesApplicationContext.getApplicationContext(serverContext.getServletContext()); + + // close it (and all underlined resources) + if (applicationContext != null) { + applicationContext.close(); + } + + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarRestRequestContext.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarRestRequestContext.java new file mode 100644 index 0000000..19950f0 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarRestRequestContext.java @@ -0,0 +1,34 @@ +package fr.ifremer.coselmar.services; + +import org.debux.webmotion.server.call.HttpContext; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class CoselmarRestRequestContext { + + protected static final String REQUEST_COSELMAR_REQUEST_CONTEXT = "coselmar_CoselmarRequestContext"; + + public static CoselmarRestRequestContext getRequestContext(HttpContext httpContext) { + + CoselmarRestRequestContext result = (CoselmarRestRequestContext) + httpContext.getRequest().getAttribute(REQUEST_COSELMAR_REQUEST_CONTEXT); + return result; + } + + public static void setRequestContext(HttpContext httpContext, + CoselmarRestRequestContext serviceContext) { + httpContext.getRequest().setAttribute(REQUEST_COSELMAR_REQUEST_CONTEXT, serviceContext); + } + + protected CoselmarServicesContext servicesContext; + + public void setServicesContext(CoselmarServicesContext servicesContext) { + this.servicesContext = servicesContext; + } + + public CoselmarServicesContext getServicesContext() { + return this.servicesContext; + } + +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarRestUtil.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarRestUtil.java new file mode 100644 index 0000000..620408f --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarRestUtil.java @@ -0,0 +1,33 @@ +package fr.ifremer.coselmar.services; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.debux.webmotion.server.call.HttpContext; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class CoselmarRestUtil { + + public static final String HEADER_ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers"; + + public static final String HEADER_ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; + + public static void prepareResponse(HttpContext context) { + + HttpServletResponse response = context.getResponse(); + response.setHeader(HttpContext.HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*"); + response.setHeader(HttpContext.HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); + + } + + public static void addOptionCorsHeaders(HttpContext context) { + + String requestHeaders = context.getHeader(HEADER_ACCESS_CONTROL_REQUEST_HEADERS); + + if (StringUtils.isNotBlank(requestHeaders)) { + context.getResponse().addHeader(HEADER_ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders); + } + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarService.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarService.java new file mode 100644 index 0000000..09da3da --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarService.java @@ -0,0 +1,9 @@ +package fr.ifremer.coselmar.services; + +/** + * Created by martel on 30/10/14. + */ +public interface CoselmarService { + + void setServicesContext(CoselmarServicesContext servicesContext); +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarServicesApplicationContext.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarServicesApplicationContext.java new file mode 100644 index 0000000..eb1aaa3 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarServicesApplicationContext.java @@ -0,0 +1,200 @@ +package fr.ifremer.coselmar.services; + +import java.io.File; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.servlet.ServletContext; + +import com.google.common.base.Preconditions; +import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; +import fr.ifremer.coselmar.persistence.CoselmarTopiaApplicationContext; +import fr.ifremer.coselmar.persistence.CoselmarTopiaPersistenceContext; +import fr.ifremer.coselmar.services.config.CoselmarServicesConfig; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.log4j.LogManager; +import org.apache.log4j.PropertyConfigurator; +import org.nuiton.i18n.I18n; +import org.nuiton.i18n.init.DefaultI18nInitializer; +import org.nuiton.i18n.init.I18nInitializer; + +import static org.apache.commons.logging.LogFactory.getLog; + + +/** + * @author ymartel <martel@codelutin.com> + */ +public class CoselmarServicesApplicationContext implements CoselmarApplicationContext { + + private static Log log = getLog(CoselmarServicesApplicationContext.class); + + protected static final String APPLICATION_CONTEXT_PARAMETER = "coselmar_CoselmarApplicationContext"; + + protected static CoselmarServicesApplicationContext applicationContext; + + public static CoselmarServicesApplicationContext getApplicationContext() { + + if (applicationContext == null) { + + CoselmarServicesConfig applicationConfig = new CoselmarServicesConfig("coselmar-services.properties"); + + Map<String, String> topiaProperties = applicationConfig.getTopiaProperties(); + + CoselmarTopiaApplicationContext coselmarTopiaApplicationContext = new CoselmarTopiaApplicationContext(topiaProperties); + + applicationContext = new CoselmarServicesApplicationContext(applicationConfig, coselmarTopiaApplicationContext); + + applicationContext.init(); + } + return applicationContext; + } + + public static CoselmarServicesApplicationContext getApplicationContext(ServletContext servletContext) { + CoselmarServicesApplicationContext result = + (CoselmarServicesApplicationContext) servletContext.getAttribute(APPLICATION_CONTEXT_PARAMETER); + return result; + } + + public static void setApplicationContext(CoselmarServicesApplicationContext applicationContext) { + CoselmarServicesApplicationContext.applicationContext = applicationContext; + } + + public static void setApplicationContext(ServletContext servletContext, + CoselmarServicesApplicationContext applicationContext) { + servletContext.setAttribute(APPLICATION_CONTEXT_PARAMETER, applicationContext); + } + + protected AtomicBoolean started; + + protected AtomicBoolean closed; + + protected CoselmarTopiaApplicationContext topiaApplicationContext; + + protected CoselmarServicesConfig applicationConfig; + + protected CoselmarServicesApplicationContext(CoselmarServicesConfig applicationConfig, CoselmarTopiaApplicationContext topiaApplicationContext) { + + Preconditions.checkNotNull(applicationConfig, "Configuration can not be null!"); + Preconditions.checkNotNull(topiaApplicationContext, "topiaApplicationContext can not be null!"); + + this.applicationConfig = applicationConfig; + this.topiaApplicationContext = topiaApplicationContext; + this.started = new AtomicBoolean(false); + this.closed = new AtomicBoolean(false); + } + + @Override + public CoselmarTopiaApplicationContext getTopiaApplicationContext() { + return this.topiaApplicationContext; + } + + @Override + public CoselmarServicesConfig getApplicationConfig() { + return this.applicationConfig; + } + + @Override + public CoselmarTopiaPersistenceContext newPersistenceContext() { + + CoselmarTopiaPersistenceContext persistenceContext = topiaApplicationContext.newPersistenceContext(); + return persistenceContext; + } + + @Override + public CoselmarServicesContext newServiceContext(CoselmarPersistenceContext persistenceContext, Locale locale) { + + DefaultCoselmarServicesContext newServiceContext = new DefaultCoselmarServicesContext(); + newServiceContext.setCoselmarServicesConfig(applicationConfig); + newServiceContext.setTopiaApplicationContext(topiaApplicationContext); + newServiceContext.setPersistenceContext(persistenceContext); + newServiceContext.setLocale(locale); + return newServiceContext; + } + + @Override + public void close() { + + if (closed.get()) { + + if (log.isWarnEnabled()) { + log.warn("Already closed"); + } + return; + } + + if (!started.get()) { + + if (log.isWarnEnabled()) { + log.warn("Not started"); + } + return; + } + + if (topiaApplicationContext != null && !topiaApplicationContext.isClosed()) { + + if (log.isInfoEnabled()) { + log.info("stopping Coselmar, will close persistence context"); + } + topiaApplicationContext.close(); + } + + closed.set(true); + started.set(false); + } + + @Override + public void init() { + + if (started.get()) { + + if (log.isWarnEnabled()) { + log.warn("Already started!"); + } + return; + } + + Preconditions.checkState(applicationConfig != null, "No configuration initialized!"); + Preconditions.checkState(topiaApplicationContext != null, "No topiaApplicationContext initialized!"); + + if (applicationConfig.isLogConfigurationProvided()) { + + File log4jConfigurationFile = applicationConfig.getLogConfigurationFile(); + + String log4jConfigurationFileAbsolutePath = log4jConfigurationFile.getAbsolutePath(); + + if (log4jConfigurationFile.exists()) { + + if (log.isInfoEnabled()) { + log.info("will use logging configuration " + log4jConfigurationFileAbsolutePath); + } + + // reset logger configuration + LogManager.resetConfiguration(); + + // use generate log config file + PropertyConfigurator.configure(log4jConfigurationFileAbsolutePath); + + log = LogFactory.getLog(CoselmarServicesApplicationContext.class); + + } else { + if (log.isWarnEnabled()) { + log.warn("there is no file " + log4jConfigurationFileAbsolutePath + ". Default logging configuration will be used."); + } + } + + } else { + log.info("will use default logging configuration"); + } + + I18nInitializer initializer = new DefaultI18nInitializer("coselmar-i18n"); + // to show none translated sentences + initializer.setMissingKeyReturnNull(true); + + I18n.init(initializer, Locale.FRANCE); + + started.set(true); + } + +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarServicesContext.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarServicesContext.java new file mode 100644 index 0000000..8ab1e39 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarServicesContext.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.services; + +import java.util.Date; +import java.util.Locale; + +import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; +import fr.ifremer.coselmar.persistence.CoselmarTopiaApplicationContext; +import fr.ifremer.coselmar.services.config.CoselmarServicesConfig; + +/** + * Created by martel on 30/10/14. + */ +public interface CoselmarServicesContext { + + Date getNow(); + + CoselmarTopiaApplicationContext getTopiaApplicationContext(); + + CoselmarPersistenceContext getPersistenceContext(); + + CoselmarServicesConfig getCoselmarServicesConfig(); + + <E extends CoselmarService> E newService(Class<E> serviceClass); + + Locale getLocale(); + + String getCleanMail(String email); + + //TODO ymartel : think about it with user management +// String generatePassword(); +// +// String generateSalt(); +// +// String encodePassword(String salt, String password); + +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarTechnicalException.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarTechnicalException.java new file mode 100644 index 0000000..3e20dbb --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarTechnicalException.java @@ -0,0 +1,24 @@ +package fr.ifremer.coselmar.services; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class CoselmarTechnicalException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public CoselmarTechnicalException() { + } + + public CoselmarTechnicalException(String message) { + super(message); + } + + public CoselmarTechnicalException(String message, Throwable cause) { + super(message, cause); + } + + public CoselmarTechnicalException(Throwable cause) { + super(cause); + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarWebServiceSupport.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarWebServiceSupport.java new file mode 100644 index 0000000..ebd0a07 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/CoselmarWebServiceSupport.java @@ -0,0 +1,73 @@ +package fr.ifremer.coselmar.services; + +import java.util.Date; +import java.util.Locale; + +import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; +import fr.ifremer.coselmar.persistence.entity.DocumentTopiaDao; +import fr.ifremer.coselmar.persistence.entity.UserTopiaDao; +import fr.ifremer.coselmar.services.config.CoselmarServicesConfig; +import fr.ifremer.coselmar.services.v1.DocumentsWebService; +import org.debux.webmotion.server.WebMotionController; + +/** + * @author ymartel <martel@codelutin.com> + */ +public abstract class CoselmarWebServiceSupport extends WebMotionController implements CoselmarService { + + protected CoselmarServicesContext servicesContext; + + @Override + public void setServicesContext(CoselmarServicesContext servicesContext) { + this.servicesContext = servicesContext; + } + + // Delegate serviceContext // + + protected Date getNow() { + return servicesContext.getNow(); + } + + protected String getCleanMail(String email) { + return servicesContext.getCleanMail(email); + } + + protected CoselmarPersistenceContext getPersistenceContext() { + return servicesContext.getPersistenceContext(); + } + + protected CoselmarServicesConfig getCoselmarServicesConfig() { + return servicesContext.getCoselmarServicesConfig(); + } + + protected Locale getLocale() { + return servicesContext.getLocale(); + } + + // Services // + + public DocumentsWebService getDocumentsService() { + return newService(DocumentsWebService.class); + } + + protected <E extends CoselmarService> E newService(Class<E> serviceClass) { + return servicesContext.newService(serviceClass); + } + + // Persistence // + protected DocumentTopiaDao getDocumentDao() { + return getPersistenceContext().getDocumentDao(); + } + + protected UserTopiaDao getUserDao() { + return getPersistenceContext().getUserDao(); + } + + public void commit() { + getPersistenceContext().commit(); + } + + public void rollback() { + getPersistenceContext().rollback(); + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/DefaultCoselmarServicesContext.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/DefaultCoselmarServicesContext.java new file mode 100644 index 0000000..3b48cc2 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/DefaultCoselmarServicesContext.java @@ -0,0 +1,102 @@ +package fr.ifremer.coselmar.services; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Date; +import java.util.Locale; + +import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; +import fr.ifremer.coselmar.persistence.CoselmarTopiaApplicationContext; +import fr.ifremer.coselmar.services.config.CoselmarServicesConfig; +import org.apache.commons.lang3.StringUtils; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class DefaultCoselmarServicesContext implements CoselmarServicesContext { + + protected CoselmarServicesConfig servicesConfig; + + protected CoselmarPersistenceContext persistenceContext; + + protected Locale locale; + + private CoselmarTopiaApplicationContext topiaApplicationContext; + + public void setCoselmarServicesConfig(CoselmarServicesConfig servicesConfig) { + this.servicesConfig = servicesConfig; + } + + public void setTopiaApplicationContext(CoselmarTopiaApplicationContext topiaApplicationContext) { + this.topiaApplicationContext = topiaApplicationContext; + } + + public void setPersistenceContext(CoselmarPersistenceContext persistenceContext) { + this.persistenceContext = persistenceContext; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } + + @Override + public Date getNow() { + Date now = new Date(); + return now; + } + + @Override + public CoselmarTopiaApplicationContext getTopiaApplicationContext() { + return this.topiaApplicationContext; + } + + @Override + public CoselmarPersistenceContext getPersistenceContext() { + return this.persistenceContext; + } + + @Override + public CoselmarServicesConfig getCoselmarServicesConfig() { + return null; + } + + @Override + public <E extends CoselmarService> E newService(Class<E> serviceClass) { + + E service; + + try { + + Constructor<E> constructor = serviceClass.getConstructor(); + + service = constructor.newInstance(); + + } catch (NoSuchMethodException e) { + + throw new CoselmarTechnicalException("all services must provide a default public constructor", e); + + } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { + + throw new CoselmarTechnicalException("unable to instantiate coselmar service", e); + + } + + service.setServicesContext(this); + + return service; + } + + @Override + public Locale getLocale() { + if (this.locale == null) { + this.locale = Locale.getDefault(); + } + return this.locale; + } + + @Override + public String getCleanMail(String email) { + return email == null ? null : StringUtils.lowerCase(email.trim()); + } + +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/config/CoselmarServicesConfig.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/config/CoselmarServicesConfig.java new file mode 100644 index 0000000..0d61eba --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/config/CoselmarServicesConfig.java @@ -0,0 +1,85 @@ +package fr.ifremer.coselmar.services.config; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import fr.ifremer.coselmar.services.CoselmarTechnicalException; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.config.ApplicationConfig; +import org.nuiton.config.ArgumentsParserException; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class CoselmarServicesConfig { + + private static final Log log = LogFactory.getLog(CoselmarServicesConfig.class); + + protected ApplicationConfig applicationConfig; + + public CoselmarServicesConfig(String filename) { + this(filename, null); + } + + public CoselmarServicesConfig(String filename, Properties defaultValues) { + applicationConfig = new ApplicationConfig(); + applicationConfig.loadDefaultOptions(CoselmarServicesConfigOption.values()); + applicationConfig.setAppName("coselmar"); + applicationConfig.setConfigFileName(filename); + if (defaultValues != null) { + for (Map.Entry<Object, Object> entry : defaultValues.entrySet()) { + + applicationConfig.setOption((String) entry.getKey(), (String) entry.getValue()); + } + } + try { + applicationConfig.parse(); + } catch (ArgumentsParserException e) { + throw new CoselmarTechnicalException(e); + } + if (log.isInfoEnabled()) { + StringBuilder builder = new StringBuilder("Coselmar configuration:"); + builder.append("\nFilename: ").append(filename); + List<CoselmarServicesConfigOption> options = Lists.newArrayList(CoselmarServicesConfigOption.values()); + for (CoselmarServicesConfigOption option : options) { + builder.append(String.format("\n%1$-40s = %2$s", + option.getKey(), + applicationConfig.getOption(option))); + } + log.info(builder.toString()); + } + } + + public Map<String, String> getTopiaProperties() { + Map<String, String> topiaParameters = Maps.newHashMap(); + Properties properties = applicationConfig.getOptionStartsWith("hibernate"); + properties.putAll(applicationConfig.getOptionStartsWith("topia")); + + for (Object o : properties.keySet()) { + String key = String.valueOf(o); + String value = applicationConfig.getOption(String.class, key); + topiaParameters.put(key, value); + } + return topiaParameters; + } + + public File getDataDirectory() { + return applicationConfig.getOptionAsFile(CoselmarServicesConfigOption.DATA_DIRECTORY.key); + } + + public boolean isLogConfigurationProvided() { + boolean logConfigurationProvided = + StringUtils.isNotBlank(applicationConfig.getOption(CoselmarServicesConfigOption.LOG_CONFIGURATION_FILE.key)); + return logConfigurationProvided; + } + + public File getLogConfigurationFile() { + return applicationConfig.getOptionAsFile(CoselmarServicesConfigOption.LOG_CONFIGURATION_FILE.key); + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/config/CoselmarServicesConfigOption.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/config/CoselmarServicesConfigOption.java new file mode 100644 index 0000000..601a276 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/config/CoselmarServicesConfigOption.java @@ -0,0 +1,85 @@ +package fr.ifremer.coselmar.services.config; + +import java.io.File; + +import org.nuiton.config.ConfigOptionDef; +import org.nuiton.i18n.I18n; + +/** + * Created by martel on 29/10/14. + */ +public enum CoselmarServicesConfigOption implements ConfigOptionDef { + + DATA_DIRECTORY( + "coselmar.data.directory", + I18n.n("coselmar.configuration.data.directory"), + "${java.io.tmpdir}/coselmar", + File.class), + + LOG_CONFIGURATION_FILE( + "coselmar.logConfigurationFile", + "Path to the logs config file", + null, + String.class), + ; + + protected final String key; + + protected final String description; + + protected final Class<?> type; + + protected String defaultValue; + + private CoselmarServicesConfigOption(String key, String description, String defaultValue, Class<?> type) { + this.key = key; + this.description = description; + this.defaultValue = defaultValue; + this.type = type; + } + + @Override + public String getKey() { + return key; + } + + @Override + public Class<?> getType() { + return type; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getDefaultValue() { + return defaultValue; + } + + @Override + public boolean isTransient() { + return false; + } + + @Override + public boolean isFinal() { + return false; + } + + @Override + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } + + @Override + public void setTransient(boolean isTransient){ + //Nothing to do + } + + @Override + public void setFinal(boolean isFinal) { + //nothing to do + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarRestRequestFilter.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarRestRequestFilter.java new file mode 100644 index 0000000..5b7b0ad --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarRestRequestFilter.java @@ -0,0 +1,110 @@ +package fr.ifremer.coselmar.services.filter; + +import java.util.Locale; + +import javax.servlet.http.HttpServletResponse; + +import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; +import fr.ifremer.coselmar.services.CoselmarRestRequestContext; +import fr.ifremer.coselmar.services.CoselmarRestUtil; +import fr.ifremer.coselmar.services.CoselmarServicesApplicationContext; +import fr.ifremer.coselmar.services.CoselmarServicesContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.debux.webmotion.server.WebMotionFilter; +import org.debux.webmotion.server.call.Call; +import org.debux.webmotion.server.call.HttpContext; +import org.debux.webmotion.server.render.Render; +import org.debux.webmotion.server.render.RenderStatus; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class CoselmarRestRequestFilter extends WebMotionFilter { + + public static final String REQUEST_PERMISSION_PARAMETER = "permission"; + + public static final String REQUEST_HEADER_SESSION_TOKEN = "X-Coselmar-Session-Token"; + + /** Logger. */ + private static final Log log = LogFactory.getLog(CoselmarRestRequestFilter.class); + + public void inject(Call call, HttpContext context) { + + prepareRequestContext(context); + + if (HttpContext.METHOD_OPTIONS.equals(context.getMethod())) { + + Render render = call.getRender(); + + if (render instanceof RenderStatus && + HttpServletResponse.SC_OK == ((RenderStatus) render).getCode()) { + + // operation accepted + CoselmarRestUtil.addOptionCorsHeaders(context); + } + } + + CoselmarRestUtil.prepareResponse(context); + + doProcess(); + + } + + protected CoselmarRestRequestContext prepareRequestContext(HttpContext context) { + + Locale locale = getUserLocale(context); + + CoselmarServicesApplicationContext applicationContext = + CoselmarServicesApplicationContext.getApplicationContext(context.getServletContext()); + + CoselmarPersistenceContext persistenceContext = + CoselmarTopiaTransactionFilter.getPersistenceContext(context.getRequest()); + + CoselmarServicesContext serviceContext = applicationContext.newServiceContext(persistenceContext, locale); + + CoselmarRestRequestContext requestContext = new CoselmarRestRequestContext(); + requestContext.setServicesContext(serviceContext); + + CoselmarRestRequestContext.setRequestContext(context, requestContext); + + return requestContext; + + } + + protected Locale getUserLocale(HttpContext context) { + String language = context.getHeader(HttpContext.HEADER_LANGUAGE); + + if (log.isInfoEnabled()) { + log.info("Found Accept-Language: " + language); + } + + // search best locale accepted by the server 'fr' or 'en' + if (language != null) { + String[] allLanguage = language.split(","); + int i = 0; + do { + language = allLanguage[i].substring(0, 2); + if ( !language.equals("fr") && !language.equals("en") ) { + // language not accepted + language = null; + } + i++; + } while ( language == null && i < allLanguage.length ); + } + + if (language == null) { + + language = Locale.FRENCH.getLanguage(); + + if (log.isInfoEnabled()) { + log.info("Use default language: " + language); + } + + } + + Locale locale = new Locale(language); + return locale; + + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarTopiaTransactionFilter.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarTopiaTransactionFilter.java new file mode 100644 index 0000000..56969e9 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarTopiaTransactionFilter.java @@ -0,0 +1,48 @@ +package fr.ifremer.coselmar.services.filter; + +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; + +import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; +import fr.ifremer.coselmar.persistence.CoselmarTopiaPersistenceContext; +import fr.ifremer.coselmar.services.CoselmarServicesApplicationContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.topia.persistence.TopiaException; +import org.nuiton.web.filter.TypedTopiaTransactionFilter; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class CoselmarTopiaTransactionFilter extends TypedTopiaTransactionFilter<CoselmarPersistenceContext> { + + private static final Log log = LogFactory.getLog(CoselmarTopiaTransactionFilter.class); + + public CoselmarTopiaTransactionFilter() { + super(CoselmarPersistenceContext.class); + } + + @Override + protected CoselmarPersistenceContext beginTransaction(ServletRequest request) throws TopiaException { + + CoselmarServicesApplicationContext applicationContext = + CoselmarServicesApplicationContext.getApplicationContext(request.getServletContext()); + + CoselmarTopiaPersistenceContext persistenceContext = applicationContext.newPersistenceContext(); + + return persistenceContext; + + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + super.init(filterConfig); + + if (log.isInfoEnabled()) { + log.info("Init Topia Filter"); + } + } + +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarRestRequestContextInjector.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarRestRequestContextInjector.java new file mode 100644 index 0000000..bef4a84 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarRestRequestContextInjector.java @@ -0,0 +1,29 @@ +package fr.ifremer.coselmar.services.injector; + +import java.lang.reflect.Type; + +import fr.ifremer.coselmar.services.CoselmarRestRequestContext; +import org.debux.webmotion.server.call.Call; +import org.debux.webmotion.server.call.HttpContext; +import org.debux.webmotion.server.handler.ExecutorParametersInjectorHandler; +import org.debux.webmotion.server.mapping.Mapping; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class CoselmarRestRequestContextInjector implements ExecutorParametersInjectorHandler.Injector { + + @Override + public CoselmarRestRequestContext getValue(Mapping m, Call call, String name, Class<?> type, Type generic) { + + CoselmarRestRequestContext result = null; + if (CoselmarRestRequestContext.class.isAssignableFrom(type)) { + HttpContext httpContext = call.getContext(); + + result = CoselmarRestRequestContext.getRequestContext(httpContext); + } + + return result; + + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarServicesInjector.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarServicesInjector.java new file mode 100644 index 0000000..7e48c8f --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarServicesInjector.java @@ -0,0 +1,32 @@ +package fr.ifremer.coselmar.services.injector; + +import java.lang.reflect.Type; + +import fr.ifremer.coselmar.services.CoselmarRestRequestContext; +import fr.ifremer.coselmar.services.CoselmarService; +import org.debux.webmotion.server.call.Call; +import org.debux.webmotion.server.call.HttpContext; +import org.debux.webmotion.server.handler.ExecutorParametersInjectorHandler; +import org.debux.webmotion.server.mapping.Mapping; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class CoselmarServicesInjector implements ExecutorParametersInjectorHandler.Injector { + + @Override + public CoselmarService getValue(Mapping m, Call call, String name, Class type, Type generic) { + + CoselmarService result = null; + if (CoselmarService.class.isAssignableFrom(type)) { + HttpContext httpContext = call.getContext(); + + CoselmarRestRequestContext requestContext = + CoselmarRestRequestContext.getRequestContext(httpContext); + result = requestContext.getServicesContext().newService(type); + } + + return result; + + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java new file mode 100644 index 0000000..331bcd4 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java @@ -0,0 +1,47 @@ +package fr.ifremer.coselmar.services.v1; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import fr.ifremer.coselmar.beans.DocumentBean; +import fr.ifremer.coselmar.services.CoselmarTechnicalException; +import fr.ifremer.coselmar.services.CoselmarWebServiceSupport; +import org.apache.commons.lang3.RandomUtils; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class DocumentsWebService extends CoselmarWebServiceSupport { + + public DocumentBean getDocument(String documentId) { + //TODO load from bdd + Date now = new Date(); + DocumentBean result = new DocumentBean("1", "fakeDocument", "no owner", "public", now); + return result; + } + + public List<DocumentBean> getDocuments() { + //TODO load from bdd + List<DocumentBean> result = new ArrayList<>(); + Date now = new Date(); + for (int i = 1; i < RandomUtils.nextInt(0, 20); i++) { + String privacy = i % 2 == 0 ? "public" : "private"; + DocumentBean document = new DocumentBean(String.valueOf(i), "fakeDocument " + i, "no owner", privacy, now); + result.add(document); + } + return result; + } + + public void addDocument(DocumentBean documentBean) { + throw new CoselmarTechnicalException("not yet implemented"); + } + + public void saveDocument(DocumentBean documentBean) { + throw new CoselmarTechnicalException("not yet implemented"); + } + + public void deleteDocument(String documentId) { + throw new CoselmarTechnicalException("not yet implemented"); + } +} diff --git a/coselmar-services/src/main/java/fr/ifremer/coselmar/services/v1/ErrorAction.java b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/v1/ErrorAction.java new file mode 100644 index 0000000..fc342e3 --- /dev/null +++ b/coselmar-services/src/main/java/fr/ifremer/coselmar/services/v1/ErrorAction.java @@ -0,0 +1,23 @@ +package fr.ifremer.coselmar.services.v1; + +import javax.servlet.http.HttpServletResponse; + +import fr.ifremer.coselmar.services.CoselmarRestUtil; +import org.debux.webmotion.server.WebMotionController; +import org.debux.webmotion.server.call.HttpContext; +import org.debux.webmotion.server.render.Render; + +/** + * @author ymartel <martel@codelutin.com> + */ +public class ErrorAction extends WebMotionController { + + public Render on500(HttpContext context, Exception e) { + + CoselmarRestUtil.prepareResponse(context); + + Render render = renderError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + return render; + + } +} diff --git a/coselmar-services/src/main/resources/coselmar-services.properties b/coselmar-services/src/main/resources/coselmar-services.properties new file mode 100644 index 0000000..f837c73 --- /dev/null +++ b/coselmar-services/src/main/resources/coselmar-services.properties @@ -0,0 +1,8 @@ + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.connection.url=jdbc:h2:file:${coselmar.data.directory}/db/coselmar +hibernate.connection.username=sa +hibernate.connection.password=sa +hibernate.connection.driver_class=org.h2.Driver +hibernate.hbm2ddl.auto=update +coselmar.version=${project.version} diff --git a/coselmar-services/src/main/resources/log4j.properties b/coselmar-services/src/main/resources/log4j.properties new file mode 100644 index 0000000..1bb5852 --- /dev/null +++ b/coselmar-services/src/main/resources/log4j.properties @@ -0,0 +1,9 @@ + +log4j.rootCategory=DEBUG, console + +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%d{hh:mm:ss} %5p (%F:%L) %m%n + +log4j.logger.fr.ifremer.coselmar=DEBUG +log4j.logger.org.debux=DEBUG diff --git a/coselmar-services/src/main/resources/mapping b/coselmar-services/src/main/resources/mapping new file mode 100644 index 0000000..c3a8ea7 --- /dev/null +++ b/coselmar-services/src/main/resources/mapping @@ -0,0 +1,34 @@ +### +# Coselmar version : ${project.version} +### + +[config] +package.filters=fr.ifremer.coselmar.services.filter +package.actions=fr.ifremer.coselmar.services.v1 +package.errors=fr.ifremer.coselmar.services.errors +server.listener.class=fr.ifremer.coselmar.services.CoselmarRestApplicationListener +#default.render=fr.ifremer.coselmar.services.CoselmarRender + +[filters] +* /* CoselmarRestRequestFilter.inject + +[errors] + +#fr.ifremer.coselmar.services.errors.CoselmarUnauthorizedException ErrorAction.on403 +#fr.ifremer.coselmar.services.CoselmarTechnicalException ErrorAction.on500 +#org.nuiton.topia.persistence.TopiaNoResultException ErrorAction.on404 + +[actions] + +# DocApi + +GET /v1/doc DocApi.showMapping + +# Documents Api + +GET /v1/documents DocumentsWebService.getDocuments +GET /v1/documents/{documentId} DocumentsWebService.getDocument +POST /v1/documents DocumentsWebService.addDocument +PUT /v1/documents/{documentId} DocumentsWebService.saveDocument +DELETE /v1/documents/{documentId} DocumentsWebService.deleteDocument + diff --git a/coselmar-services/src/main/webapp/WEB-INF/web.xml b/coselmar-services/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..c6b9278 --- /dev/null +++ b/coselmar-services/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<web-app version="3.0" id="coselmar" + xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee + http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> + + <display-name>Coselmar REST Api</display-name> + + <filter> + <filter-name>topiaTransaction</filter-name> + <filter-class> + fr.ifremer.coselmar.services.filter.CoselmarTopiaTransactionFilter + </filter-class> + </filter> + + <filter-mapping> + <filter-name>topiaTransaction</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + +</web-app> \ No newline at end of file diff --git a/pom.xml b/pom.xml index ddefe08..ca29340 100644 --- a/pom.xml +++ b/pom.xml @@ -117,6 +117,17 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- customized versions --> <webmotionVersion>2.4.1-20140826-pollen2</webmotionVersion> + <nuitonI18nVersion>3.3</nuitonI18nVersion> + <eugenePluginVersion>2.13</eugenePluginVersion> + <topiaVersion>3.0-beta-12</topiaVersion> + + <nuitonWebVersion>1.17</nuitonWebVersion> + <nuitonUtilsVersion>3.0-rc-7</nuitonUtilsVersion> + <nuitonConfigVersion>3.0-rc-1</nuitonConfigVersion> + <nuitonCsvVersion>3.0-alpha-3</nuitonCsvVersion> + <nuitonValidatorVersion>3.0-rc-1</nuitonValidatorVersion> + <nuitonConvertorVersion>1.0</nuitonConvertorVersion> + </properties> @@ -162,7 +173,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <dependency> <groupId>org.nuiton</groupId> <artifactId>nuiton-utils</artifactId> - <version>3.0-rc-8</version> + <version>${nuitonUtilsVersion}</version> </dependency> <dependency> <groupId>org.nuiton</groupId> @@ -172,12 +183,12 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <dependency> <groupId>org.nuiton</groupId> <artifactId>nuiton-config</artifactId> - <version>3.0-rc-1</version> + <version>${nuitonConfigVersion}</version> </dependency> <dependency> <groupId>org.nuiton</groupId> <artifactId>nuiton-converter</artifactId> - <version>1.0</version> + <version>${nuitonConvertorVersion}</version> </dependency> <dependency> <groupId>org.nuiton.i18n</groupId> @@ -189,6 +200,12 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <artifactId>nuiton-validator</artifactId> <version>${nuitonValidatorVersion}</version> </dependency> + <dependency> + <groupId>org.nuiton.web</groupId> + <artifactId>nuiton-web</artifactId> + <version>${nuitonWebVersion}</version> + <scope>compile</scope> + </dependency> <!-- Commons --> <dependency> @@ -222,6 +239,11 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <version>17.0</version> </dependency> <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.2.4</version> + </dependency> + <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>4.1.0</version> @@ -239,6 +261,11 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> </exclusion> </exclusions> </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>3.1.0</version> + </dependency> <!-- Logging --> <dependency> @@ -256,6 +283,11 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <artifactId>slf4j-jcl</artifactId> <version>${slf4jVersion}</version> </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <version>${slf4jVersion}</version> + </dependency> <!-- Test --> <dependency> -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.