This is an automated email from the git hooks/post-receive script. New commit to branch refonte-rest in repository coselmar. See https://gitlab.nuiton.org/codelutin/coselmar.git commit 850661b810bac22323892a92d266156b067d00cb Author: Yannick Martel <martel@©odelutin.com> Date: Tue Jun 4 11:49:40 2019 +0200 let's migrate from old webmotion to Resteasy for REST APIs --- coselmar-rest/pom.xml | 75 +++- .../fr/ifremer/coselmar/beans/DocumentBean.java | 2 +- .../ifremer/coselmar/beans/DocumentSearchBean.java | 12 +- .../ifremer/coselmar/beans/QuestionSearchBean.java | 2 + .../java/fr/ifremer/coselmar/beans/UserBean.java | 2 + .../fr/ifremer/coselmar/beans/UserSearchBean.java | 6 + .../coselmar/converter/JacksonMapperUtil.java | 29 ++ .../providers/CoselmarJacksonProvider.java | 32 ++ .../providers/CoselmarParamConverterProvider.java | 92 +++++ .../coselmar/providers/DateParamConverter.java | 28 ++ .../providers/DocumentBeanParamConverter.java | 36 ++ .../DocumentSearchBeanParamConverter.java | 36 ++ .../DocumentSearchExampleParamConverter.java | 36 ++ .../coselmar/providers/LinkBeanParamConverter.java | 36 ++ .../providers/QuestionBeanParamConverter.java | 36 ++ .../QuestionSearchBeanParamConverter.java | 36 ++ .../QuestionSearchExampleParamConverter.java | 36 ++ .../providers/SearchExampleParamConverter.java | 36 ++ .../coselmar/providers/UserBeanParamConverter.java | 36 ++ .../providers/UserSearchBeanParamConverter.java | 36 ++ .../coselmar/services/CoselmarApplication.java | 92 +++++ .../ifremer/coselmar/services/CoselmarRender.java | 75 ---- .../services/CoselmarRestApplicationListener.java | 62 ++- .../services/CoselmarRestRequestContext.java | 58 --- .../coselmar/services/CoselmarRestUtil.java | 61 --- .../CoselmarServicesApplicationContext.java | 21 +- .../services/CoselmarWebServiceSupport.java | 117 +----- .../errors/CoselmarTechnicalExceptionMapper.java | 23 ++ .../errors/InvalidCredentialExceptionMapper.java | 22 + .../errors/MailAlreadyExistingExceptionMapper.java | 22 + .../services/errors/NoResultExceptionMapper.java | 22 + .../errors/TopiaNoResultExceptionMapper.java | 23 ++ .../errors/UnauthorizedExceptionMapper.java | 22 + .../services/filter/CORSResponseFilter.java | 46 +++ .../services/filter/CoselmarRestRequestFilter.java | 92 ++--- .../filter/CoselmarTopiaTransactionFilter.java | 7 + .../CoselmarRestRequestContextInjector.java | 53 --- .../injector/CoselmarServicesInjector.java | 56 --- .../coselmar/services/v1/AdminWebService.java | 52 ++- .../coselmar/services/v1/DocumentsWebService.java | 431 ++++++++++++-------- .../ifremer/coselmar/services/v1/ErrorAction.java | 83 ---- .../coselmar/services/v1/GeneralWebService.java | 16 +- .../coselmar/services/v1/HealthService.java | 22 +- .../coselmar/services/v1/QuestionsWebService.java | 446 +++++++++++++-------- .../coselmar/services/v1/UsersWebService.java | 240 ++++++----- coselmar-rest/src/main/resources/mapping | 90 ++--- .../services/AbstractCoselmarWebServiceTest.java | 26 +- .../coselmar/services/QuestionsWebServiceTest.java | 441 ++++++++++---------- .../coselmar/services/UsersWebServiceTest.java | 106 +++-- .../services/v1/DocumentsWebServiceTest.java | 4 +- .../src/main/webapp/js/coselmar-controllers.js | 1 + pom.xml | 88 +++- 52 files changed, 2143 insertions(+), 1417 deletions(-) diff --git a/coselmar-rest/pom.xml b/coselmar-rest/pom.xml index 0fa57c0..e4e3ba4 100644 --- a/coselmar-rest/pom.xml +++ b/coselmar-rest/pom.xml @@ -115,9 +115,57 @@ </dependency> <!-- web part --> + <!-- REASTEasy, for webservices --> <dependency> - <groupId>org.debux.webmotion</groupId> - <artifactId>webmotion</artifactId> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-jaxrs</artifactId> + </dependency> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-jaxb-provider</artifactId> + <scope>runtime</scope> + </dependency> + <!-- Multipart support --> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-multipart-provider</artifactId> + </dependency> + <!-- to run test on API --> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-undertow</artifactId> + <scope>test</scope> + </dependency> + + <!-- transitive dependency from resteasy --> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + </dependency> + <!--<dependency>--> + <!--<groupId>org.jboss.spec.javax.ws.rs</groupId>--> + <!--<artifactId>jboss-jaxrs-api_2.1_spec</artifactId>--> + <!--<version>1.0.0.Final</version>--> + <!--</dependency>--> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + </dependency> + + <!-- needed for Servlet 3 --> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-servlet-initializer</artifactId> + <scope>runtime</scope> + </dependency> + <!-- needed for JSON response --> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-jackson2-provider</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> @@ -190,24 +238,6 @@ <groupId>org.nuiton.topia</groupId> <artifactId>topia-junit</artifactId> </dependency> - <dependency> - <groupId>org.debux.webmotion</groupId> - <artifactId>webmotion-unittest</artifactId> - <exclusions> - <exclusion> - <groupId>org.apache.tomcat.embed</groupId> - <artifactId>tomcat-embed-logging-juli</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.tomcat.embed</groupId> - <artifactId>tomcat-embed-jasper</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jdt.core.compiler</groupId> - <artifactId>ecj</artifactId> - </exclusion> - </exclusions> - </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> @@ -218,6 +248,11 @@ <artifactId>fluent-hc</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentBean.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentBean.java index 5ec0d92..c7cef09 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentBean.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentBean.java @@ -68,7 +68,7 @@ public class DocumentBean implements Serializable { return new DocumentBean(); } - private DocumentBean(){} + public DocumentBean(){} public DocumentBean(String id, String name, String ownerName, String ownerId, String privacy, Date depositDate, Collection<String> keywords, diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentSearchBean.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentSearchBean.java index 17a7599..718ef0e 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentSearchBean.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/DocumentSearchBean.java @@ -47,13 +47,15 @@ public class DocumentSearchBean extends DocumentBean { protected Date publicationBeforeDate; + public DocumentSearchBean() { + } public DocumentSearchBean(String id, String name, String ownerName, String ownerId, String privacy, - Date depositDate, Collection<String> keywords, - String type, String summary, String language, Date publicationDate, - String authors, String license, String copyright, - boolean withFile, String mimeType, String externalUrl, - String comment, String fileName, String citation) { + Date depositDate, Collection<String> keywords, + String type, String summary, String language, Date publicationDate, + String authors, String license, String copyright, + boolean withFile, String mimeType, String externalUrl, + String comment, String fileName, String citation) { super(id, name, ownerName, ownerId, privacy, depositDate, keywords, type, summary, language, publicationDate, authors, license, copyright, withFile, mimeType, externalUrl, comment, fileName, citation); } diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/QuestionSearchBean.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/QuestionSearchBean.java index d1fd0f7..39e7029 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/QuestionSearchBean.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/QuestionSearchBean.java @@ -51,6 +51,8 @@ public class QuestionSearchBean extends QuestionBean { protected String contributorId; protected String clientId; + public QuestionSearchBean() { + } public Integer getLimit() { return limit; diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/UserBean.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/UserBean.java index d4a2c7e..0a91e9f 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/UserBean.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/UserBean.java @@ -52,6 +52,8 @@ public class UserBean implements Serializable { protected String phoneNumber; protected boolean active; + public UserBean() {} + public UserBean(String id, String firstName, String name, String mail, String phoneNumber, String role, String qualification, String organization, boolean active) { diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/UserSearchBean.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/UserSearchBean.java index e4d1eb9..49d7f81 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/UserSearchBean.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/beans/UserSearchBean.java @@ -38,6 +38,8 @@ public class UserSearchBean extends UserBean { protected List<String> fullTextSearch; protected boolean activeAndInactive; + public UserSearchBean() {} + public UserSearchBean(String id, String firstName, String name, String mail, String phoneNumber, String role, String qualification, String organization, boolean active) { super(id, firstName, name, mail, phoneNumber, role, qualification, organization, active); } @@ -73,4 +75,8 @@ public class UserSearchBean extends UserBean { public void setActiveAndInactive(boolean activeAndInactive) { this.activeAndInactive = activeAndInactive; } + + public void setShowDisable(boolean showDisable) { + this.activeAndInactive = showDisable; + } } diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/converter/JacksonMapperUtil.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/converter/JacksonMapperUtil.java new file mode 100644 index 0000000..ad7f2c4 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/converter/JacksonMapperUtil.java @@ -0,0 +1,29 @@ +package fr.ifremer.coselmar.converter; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class JacksonMapperUtil { + + public static ObjectMapper getMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + objectMapper.enable(SerializationFeature.EAGER_SERIALIZER_FETCH); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker() + .withFieldVisibility(JsonAutoDetect.Visibility.ANY) + .withGetterVisibility(JsonAutoDetect.Visibility.NONE) + .withSetterVisibility(JsonAutoDetect.Visibility.ANY) + .withCreatorVisibility(JsonAutoDetect.Visibility.NONE)); + + return objectMapper; + + } + +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/CoselmarJacksonProvider.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/CoselmarJacksonProvider.java new file mode 100644 index 0000000..a288117 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/CoselmarJacksonProvider.java @@ -0,0 +1,32 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; +import org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider; +import org.nuiton.util.pagination.PaginationResult; + +import javax.ws.rs.Consumes; +import javax.ws.rs.ProcessingException; +import javax.ws.rs.Produces; +import javax.ws.rs.ext.ParamConverter; +import javax.ws.rs.ext.Provider; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +@Provider +@Consumes({"application/json", "application/*+json", "text/json"}) +@Produces({"application/json", "application/*+json", "text/json"}) +public class CoselmarJacksonProvider extends ResteasyJackson2Provider { + + public CoselmarJacksonProvider() { + ObjectMapper mapper = JacksonMapperUtil.getMapper(); + this.setMapper(mapper); + } + +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/CoselmarParamConverterProvider.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/CoselmarParamConverterProvider.java new file mode 100644 index 0000000..3ede74f --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/CoselmarParamConverterProvider.java @@ -0,0 +1,92 @@ +package fr.ifremer.coselmar.providers; + +/*- + * #%L + * DEPHY-Graph + * %% + * Copyright (C) 2018 - 2019 Inra + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import fr.ifremer.coselmar.beans.DocumentBean; +import fr.ifremer.coselmar.beans.DocumentSearchBean; +import fr.ifremer.coselmar.beans.DocumentSearchExample; +import fr.ifremer.coselmar.beans.LinkBean; +import fr.ifremer.coselmar.beans.QuestionBean; +import fr.ifremer.coselmar.beans.QuestionSearchBean; +import fr.ifremer.coselmar.beans.QuestionSearchExample; +import fr.ifremer.coselmar.beans.SearchExample; +import fr.ifremer.coselmar.beans.UserBean; +import fr.ifremer.coselmar.beans.UserSearchBean; +import org.nuiton.util.pagination.PaginationResult; + +import javax.ws.rs.ext.ParamConverter; +import javax.ws.rs.ext.ParamConverterProvider; +import javax.ws.rs.ext.Provider; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Date; + +/** + * @author ymartel (martel@codelutin.com) + */ +@Provider +public class CoselmarParamConverterProvider implements ParamConverterProvider { + + @Override + public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) { + + // Specific converter for Metadata param. + if (rawType.isAssignableFrom(Date.class)) { + return (ParamConverter<T>) new DateParamConverter(); + + } else if (rawType.isAssignableFrom(UserBean.class)) { + return (ParamConverter<T>) new UserBeanParamConverter(); + + } else if (rawType.isAssignableFrom(UserSearchBean.class)) { + return (ParamConverter<T>) new UserSearchBeanParamConverter(); + + } else if (rawType.isAssignableFrom(QuestionBean.class)) { + return (ParamConverter<T>) new QuestionBeanParamConverter(); + + } else if (rawType.isAssignableFrom(QuestionSearchBean.class)) { + return (ParamConverter<T>) new QuestionSearchBeanParamConverter(); + + } else if (rawType.isAssignableFrom(SearchExample.class)) { + return (ParamConverter<T>) new SearchExampleParamConverter(); + + } else if (rawType.isAssignableFrom(QuestionSearchExample.class)) { + return (ParamConverter<T>) new QuestionSearchExampleParamConverter(); + + } else if (rawType.isAssignableFrom(DocumentSearchExample.class)) { + return (ParamConverter<T>) new DocumentSearchExampleParamConverter(); + + } else if (rawType.isAssignableFrom(DocumentBean.class)) { + return (ParamConverter<T>) new DocumentBeanParamConverter(); + + } else if (rawType.isAssignableFrom(DocumentSearchBean.class)) { + return (ParamConverter<T>) new DocumentSearchBeanParamConverter(); + + } else if (rawType.isAssignableFrom(LinkBean.class)) { + return (ParamConverter<T>) new LinkBeanParamConverter(); + + } + + return null; + } + +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DateParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DateParamConverter.java new file mode 100644 index 0000000..df9ae49 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DateParamConverter.java @@ -0,0 +1,28 @@ +package fr.ifremer.coselmar.providers; + +import org.apache.commons.lang3.StringUtils; + +import javax.ws.rs.ext.ParamConverter; +import java.util.Date; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class DateParamConverter implements ParamConverter<Date> { + @Override + public Date fromString(String value) { + if (StringUtils.isNotBlank(value)) { + long time = Long.parseLong(value); + return new Date(time); + } + return null; + } + + @Override + public String toString(Date value) { + if (value != null) { + return String.valueOf(value.getTime()); + } + return null; + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DocumentBeanParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DocumentBeanParamConverter.java new file mode 100644 index 0000000..a611f97 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DocumentBeanParamConverter.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.coselmar.beans.DocumentBean; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.ext.ParamConverter; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class DocumentBeanParamConverter implements ParamConverter<DocumentBean> { + + protected final ObjectMapper mapper = JacksonMapperUtil.getMapper(); + + @Override + public DocumentBean fromString(String value) { + try { + return mapper.readerFor(DocumentBean.class).readValue(value); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + @Override + public String toString(DocumentBean value) { + try { + return mapper.writer().writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new ProcessingException(e); + } + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DocumentSearchBeanParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DocumentSearchBeanParamConverter.java new file mode 100644 index 0000000..f36875a --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DocumentSearchBeanParamConverter.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.coselmar.beans.DocumentSearchBean; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.ext.ParamConverter; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class DocumentSearchBeanParamConverter implements ParamConverter<DocumentSearchBean> { + + protected final ObjectMapper mapper = JacksonMapperUtil.getMapper(); + + @Override + public DocumentSearchBean fromString(String value) { + try { + return mapper.readerFor(DocumentSearchBean.class).readValue(value); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + @Override + public String toString(DocumentSearchBean value) { + try { + return mapper.writer().writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new ProcessingException(e); + } + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DocumentSearchExampleParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DocumentSearchExampleParamConverter.java new file mode 100644 index 0000000..818abc9 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/DocumentSearchExampleParamConverter.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.coselmar.beans.DocumentSearchExample; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.ext.ParamConverter; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class DocumentSearchExampleParamConverter implements ParamConverter<DocumentSearchExample> { + + protected final ObjectMapper mapper = JacksonMapperUtil.getMapper(); + + @Override + public DocumentSearchExample fromString(String value) { + try { + return mapper.readerFor(DocumentSearchExample.class).readValue(value); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + @Override + public String toString(DocumentSearchExample value) { + try { + return mapper.writer().writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new ProcessingException(e); + } + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/LinkBeanParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/LinkBeanParamConverter.java new file mode 100644 index 0000000..8fae188 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/LinkBeanParamConverter.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.coselmar.beans.LinkBean; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.ext.ParamConverter; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class LinkBeanParamConverter implements ParamConverter<LinkBean> { + + protected final ObjectMapper mapper = JacksonMapperUtil.getMapper(); + + @Override + public LinkBean fromString(String value) { + try { + return mapper.readerFor(LinkBean.class).readValue(value); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + @Override + public String toString(LinkBean value) { + try { + return mapper.writer().writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new ProcessingException(e); + } + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/QuestionBeanParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/QuestionBeanParamConverter.java new file mode 100644 index 0000000..95889ec --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/QuestionBeanParamConverter.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.coselmar.beans.QuestionBean; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.ext.ParamConverter; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class QuestionBeanParamConverter implements ParamConverter<QuestionBean> { + + protected final ObjectMapper mapper = JacksonMapperUtil.getMapper(); + + @Override + public QuestionBean fromString(String value) { + try { + return mapper.readerFor(QuestionBean.class).readValue(value); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + @Override + public String toString(QuestionBean value) { + try { + return mapper.writer().writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new ProcessingException(e); + } + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/QuestionSearchBeanParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/QuestionSearchBeanParamConverter.java new file mode 100644 index 0000000..43b525a --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/QuestionSearchBeanParamConverter.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.coselmar.beans.QuestionSearchBean; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.ext.ParamConverter; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class QuestionSearchBeanParamConverter implements ParamConverter<QuestionSearchBean> { + + protected final ObjectMapper mapper = JacksonMapperUtil.getMapper(); + + @Override + public QuestionSearchBean fromString(String value) { + try { + return mapper.readerFor(QuestionSearchBean.class).readValue(value); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + @Override + public String toString(QuestionSearchBean value) { + try { + return mapper.writer().writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new ProcessingException(e); + } + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/QuestionSearchExampleParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/QuestionSearchExampleParamConverter.java new file mode 100644 index 0000000..6aa3170 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/QuestionSearchExampleParamConverter.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.coselmar.beans.QuestionSearchExample; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.ext.ParamConverter; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class QuestionSearchExampleParamConverter implements ParamConverter<QuestionSearchExample> { + + protected final ObjectMapper mapper = JacksonMapperUtil.getMapper(); + + @Override + public QuestionSearchExample fromString(String value) { + try { + return mapper.readerFor(QuestionSearchExample.class).readValue(value); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + @Override + public String toString(QuestionSearchExample value) { + try { + return mapper.writer().writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new ProcessingException(e); + } + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/SearchExampleParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/SearchExampleParamConverter.java new file mode 100644 index 0000000..7071aec --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/SearchExampleParamConverter.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.coselmar.beans.SearchExample; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.ext.ParamConverter; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class SearchExampleParamConverter implements ParamConverter<SearchExample> { + + protected final ObjectMapper mapper = JacksonMapperUtil.getMapper(); + + @Override + public SearchExample fromString(String value) { + try { + return mapper.readerFor(SearchExample.class).readValue(value); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + @Override + public String toString(SearchExample value) { + try { + return mapper.writer().writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new ProcessingException(e); + } + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/UserBeanParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/UserBeanParamConverter.java new file mode 100644 index 0000000..3b06080 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/UserBeanParamConverter.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.coselmar.beans.UserBean; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.ext.ParamConverter; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class UserBeanParamConverter implements ParamConverter<UserBean> { + + protected final ObjectMapper mapper = JacksonMapperUtil.getMapper(); + + @Override + public UserBean fromString(String value) { + try { + return mapper.readerFor(UserBean.class).readValue(value); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + @Override + public String toString(UserBean value) { + try { + return mapper.writer().writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new ProcessingException(e); + } + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/UserSearchBeanParamConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/UserSearchBeanParamConverter.java new file mode 100644 index 0000000..1a3956b --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/providers/UserSearchBeanParamConverter.java @@ -0,0 +1,36 @@ +package fr.ifremer.coselmar.providers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.coselmar.beans.UserSearchBean; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; + +import javax.ws.rs.ProcessingException; +import javax.ws.rs.ext.ParamConverter; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class UserSearchBeanParamConverter implements ParamConverter<UserSearchBean> { + + protected final ObjectMapper mapper = JacksonMapperUtil.getMapper(); + + @Override + public UserSearchBean fromString(String value) { + try { + return mapper.readerFor(UserSearchBean.class).readValue(value); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + @Override + public String toString(UserSearchBean value) { + try { + return mapper.writer().writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new ProcessingException(e); + } + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarApplication.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarApplication.java new file mode 100644 index 0000000..c5ff69b --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarApplication.java @@ -0,0 +1,92 @@ +package fr.ifremer.coselmar.services; + +import fr.ifremer.coselmar.beans.DocumentBean; +import fr.ifremer.coselmar.beans.DocumentSearchBean; +import fr.ifremer.coselmar.beans.DocumentSearchExample; +import fr.ifremer.coselmar.beans.LinkBean; +import fr.ifremer.coselmar.beans.QuestionBean; +import fr.ifremer.coselmar.beans.QuestionSearchBean; +import fr.ifremer.coselmar.beans.QuestionSearchExample; +import fr.ifremer.coselmar.beans.SearchExample; +import fr.ifremer.coselmar.beans.UserBean; +import fr.ifremer.coselmar.beans.UserSearchBean; +import fr.ifremer.coselmar.providers.CoselmarParamConverterProvider; +import fr.ifremer.coselmar.providers.CoselmarJacksonProvider; +import fr.ifremer.coselmar.services.errors.CoselmarTechnicalExceptionMapper; +import fr.ifremer.coselmar.services.errors.InvalidCredentialExceptionMapper; +import fr.ifremer.coselmar.services.errors.MailAlreadyExistingExceptionMapper; +import fr.ifremer.coselmar.services.errors.NoResultExceptionMapper; +import fr.ifremer.coselmar.services.errors.TopiaNoResultExceptionMapper; +import fr.ifremer.coselmar.services.errors.UnauthorizedExceptionMapper; +import fr.ifremer.coselmar.services.filter.CORSResponseFilter; +import fr.ifremer.coselmar.services.filter.CoselmarRestRequestFilter; +import fr.ifremer.coselmar.services.filter.CoselmarTopiaTransactionFilter; +import fr.ifremer.coselmar.services.v1.AdminWebService; +import fr.ifremer.coselmar.services.v1.DocumentsWebService; +import fr.ifremer.coselmar.services.v1.GeneralWebService; +import fr.ifremer.coselmar.services.v1.HealthService; +import fr.ifremer.coselmar.services.v1.QuestionsWebService; +import fr.ifremer.coselmar.services.v1.UsersWebService; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; +import java.util.HashSet; +import java.util.Set; + +/** + * @author ymartel (martel@codelutin.com) + */ +@ApplicationPath("") +public class CoselmarApplication extends Application { + + Set<Object> singletons; + + public CoselmarApplication() {} + + @Override + public Set<Object> getSingletons() { + if (singletons == null) { + singletons = new HashSet<>(); + + singletons.add(new AdminWebService()); + singletons.add(new DocumentsWebService()); + singletons.add(new GeneralWebService()); + singletons.add(new QuestionsWebService()); + singletons.add(new UsersWebService()); + singletons.add(new HealthService()); + + singletons.add(new CoselmarRestRequestFilter()); + singletons.add(new CORSResponseFilter()); + singletons.add(new CoselmarTopiaTransactionFilter()); + + singletons.add(new CoselmarParamConverterProvider()); + singletons.add(new CoselmarJacksonProvider()); + } + return singletons; + } + + @Override + public Set<Class<?>> getClasses() { + Set<Class<?>> classes = new HashSet<>(); + + classes.add(InvalidCredentialExceptionMapper.class); + classes.add(UnauthorizedExceptionMapper.class); + classes.add(NoResultExceptionMapper.class); + classes.add(MailAlreadyExistingExceptionMapper.class); + classes.add(CoselmarTechnicalExceptionMapper.class); + classes.add(TopiaNoResultExceptionMapper.class); + + classes.add(UserBean.class); + classes.add(UserSearchBean.class); + classes.add(DocumentBean.class); + classes.add(DocumentSearchBean.class); + classes.add(QuestionBean.class); + classes.add(QuestionSearchBean.class); + classes.add(QuestionSearchExample.class); + classes.add(DocumentSearchExample.class); + classes.add(SearchExample.class); + classes.add(LinkBean.class); + + return classes; + } +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRender.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRender.java deleted file mode 100644 index 8b9337f..0000000 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRender.java +++ /dev/null @@ -1,75 +0,0 @@ -package fr.ifremer.coselmar.services; - -/* - * #%L - * Coselmar :: Rest Services - * $Id:$ - * $HeadURL:$ - * %% - * Copyright (C) 2014 Ifremer, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import fr.ifremer.coselmar.converter.JsonHelper; -import org.debux.webmotion.server.call.Call; -import org.debux.webmotion.server.call.HttpContext; -import org.debux.webmotion.server.mapping.Mapping; -import org.debux.webmotion.server.render.Render; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; - -/** - * @author ymartel <martel@codelutin.com> - */ -public class CoselmarRender<T> extends Render { - - protected T model; - - public CoselmarRender(T model) { - this.model = model; - } - - @Override - public void create(Mapping mapping, Call call) throws IOException, ServletException { - - HttpContext context = call.getContext(); - HttpServletResponse response = context.getResponse(); - response.setContentType("application/json"); - - CoselmarServicesApplicationContext applicationContext = - CoselmarServicesApplicationContext.getApplicationContext(context.getServletContext()); - - //TODO ymartel 20141030 : think about formException render -// if (model instanceof InvalidFormException) { -// -// response.setStatus(HttpServletResponse.SC_BAD_REQUEST); -// -// } - - boolean devMode = applicationContext.getApplicationConfig().isDevMode(); - - JsonHelper gson = new JsonHelper(devMode); - String json = gson.toJson(model); - - PrintWriter out = context.getOut(); - out.print(json); - - } -} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java index c6396e5..3a858db 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestApplicationListener.java @@ -33,22 +33,17 @@ import fr.ifremer.coselmar.beans.QuestionSearchBean; import fr.ifremer.coselmar.beans.QuestionSearchExample; import fr.ifremer.coselmar.beans.UserBean; import fr.ifremer.coselmar.beans.UserSearchBean; -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; -import java.util.Date; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; import java.util.Set; /** * @author ymartel <martel@codelutin.com> */ -public class CoselmarRestApplicationListener implements WebMotionServerListener { +@WebListener +public class CoselmarRestApplicationListener implements ServletContextListener { protected static final Set<Class<?>> BEAN_TYPES = Sets.<Class<?>>newHashSet( DocumentBean.class, @@ -62,39 +57,39 @@ public class CoselmarRestApplicationListener implements WebMotionServerListener ); @Override - public void onStart(Mapping mapping, ServerContext serverContext) { + public void contextInitialized(ServletContextEvent sce) { // init application context // CoselmarServicesApplicationContext applicationContext = - CoselmarServicesApplicationContext.getApplicationContext(); - - 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 // - serverContext.addInjector(new CoselmarRestRequestContextInjector()); - serverContext.addInjector(new CoselmarServicesInjector()); + CoselmarServicesApplicationContext.getInstance(); + + CoselmarServicesApplicationContext.setApplicationContext(sce.getServletContext(), applicationContext); + +// // init converters // +// +// sce.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 // +// serverContext.addInjector(new CoselmarRestRequestContextInjector()); +// serverContext.addInjector(new CoselmarServicesInjector()); } @Override - public void onStop(ServerContext serverContext) { + public void contextDestroyed(ServletContextEvent sce) { // Get application context CoselmarServicesApplicationContext applicationContext = - CoselmarServicesApplicationContext.getApplicationContext(serverContext.getServletContext()); + CoselmarServicesApplicationContext.getApplicationContext(sce.getServletContext()); // close it (and all underlined resources) if (applicationContext != null) { @@ -102,4 +97,5 @@ public class CoselmarRestApplicationListener implements WebMotionServerListener } } + } diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestRequestContext.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestRequestContext.java deleted file mode 100644 index a6eab47..0000000 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestRequestContext.java +++ /dev/null @@ -1,58 +0,0 @@ -package fr.ifremer.coselmar.services; - -/* - * #%L - * Coselmar :: Rest Services - * $Id:$ - * $HeadURL:$ - * %% - * Copyright (C) 2014 Ifremer, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -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 requestContext) { - httpContext.getRequest().setAttribute(REQUEST_COSELMAR_REQUEST_CONTEXT, requestContext); - } - - protected CoselmarServicesContext servicesContext; - - public void setServicesContext(CoselmarServicesContext servicesContext) { - this.servicesContext = servicesContext; - } - - public CoselmarServicesContext getServicesContext() { - return this.servicesContext; - } - -} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestUtil.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestUtil.java deleted file mode 100644 index 005fc6e..0000000 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarRestUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.ifremer.coselmar.services; - -/* - * #%L - * Coselmar :: Rest Services - * $Id:$ - * $HeadURL:$ - * %% - * Copyright (C) 2014 Ifremer, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.apache.commons.lang3.StringUtils; -import org.debux.webmotion.server.call.HttpContext; - -import javax.servlet.http.HttpServletResponse; - -/** - * @author ymartel <martel@codelutin.com> - */ -public final 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"; - - private CoselmarRestUtil() { - throw new IllegalAccessError("Utility class"); - } - - 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-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarServicesApplicationContext.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarServicesApplicationContext.java index e1b414f..373d232 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarServicesApplicationContext.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarServicesApplicationContext.java @@ -37,6 +37,8 @@ import org.apache.log4j.PropertyConfigurator; import org.nuiton.i18n.I18n; import org.nuiton.i18n.init.DefaultI18nInitializer; import org.nuiton.i18n.init.I18nInitializer; +import org.nuiton.topia.persistence.BeanTopiaConfiguration; +import org.nuiton.topia.persistence.TopiaConfigurationBuilder; import javax.servlet.ServletContext; import java.io.File; @@ -56,25 +58,26 @@ public class CoselmarServicesApplicationContext implements CoselmarApplicationCo protected static final String APPLICATION_CONTEXT_PARAMETER = "coselmar_CoselmarApplicationContext"; - protected static CoselmarServicesApplicationContext applicationContext; + protected static CoselmarServicesApplicationContext instance; - public static CoselmarServicesApplicationContext getApplicationContext() { + public static CoselmarServicesApplicationContext getInstance() { - if (applicationContext == null) { + if (instance == null) { CoselmarServicesConfig applicationConfig = new CoselmarServicesConfig("coselmar-services.properties"); Map<String, String> topiaProperties = applicationConfig.getTopiaProperties(); - CoselmarTopiaApplicationContext coselmarTopiaApplicationContext = new CoselmarTopiaApplicationContext(topiaProperties); + BeanTopiaConfiguration topiaConfiguration = new TopiaConfigurationBuilder().readMap(topiaProperties); + CoselmarTopiaApplicationContext coselmarTopiaApplicationContext = new CoselmarTopiaApplicationContext(topiaConfiguration); LuceneUtils luceneUtils = new LuceneUtils(applicationConfig); - applicationContext = new CoselmarServicesApplicationContext(applicationConfig, coselmarTopiaApplicationContext, luceneUtils); + instance = new CoselmarServicesApplicationContext(applicationConfig, coselmarTopiaApplicationContext, luceneUtils); - applicationContext.init(); + instance.init(); } - return applicationContext; + return instance; } public static CoselmarServicesApplicationContext getApplicationContext(ServletContext servletContext) { @@ -83,8 +86,8 @@ public class CoselmarServicesApplicationContext implements CoselmarApplicationCo return result; } - public static void setApplicationContext(CoselmarServicesApplicationContext applicationContext) { - CoselmarServicesApplicationContext.applicationContext = applicationContext; + public static void setInstance(CoselmarServicesApplicationContext instance) { + CoselmarServicesApplicationContext.instance = instance; } public static void setApplicationContext(ServletContext servletContext, diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarWebServiceSupport.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarWebServiceSupport.java index 8bbcf8c..87f1d8d 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarWebServiceSupport.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/CoselmarWebServiceSupport.java @@ -27,35 +27,25 @@ package fr.ifremer.coselmar.services; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.JWTVerifyException; import fr.ifremer.coselmar.beans.UserWebToken; -import fr.ifremer.coselmar.config.CoselmarServicesConfig; import fr.ifremer.coselmar.exceptions.CoselmarTechnicalException; import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; import fr.ifremer.coselmar.persistence.entity.CoselmarUser; -import fr.ifremer.coselmar.persistence.entity.CoselmarUserGroupTopiaDao; -import fr.ifremer.coselmar.persistence.entity.CoselmarUserTopiaDao; -import fr.ifremer.coselmar.persistence.entity.DocumentTopiaDao; -import fr.ifremer.coselmar.persistence.entity.QuestionTopiaDao; import fr.ifremer.coselmar.services.errors.InvalidCredentialException; -import fr.ifremer.coselmar.services.v1.DocumentsWebService; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.debux.webmotion.server.WebMotionController; -import org.debux.webmotion.server.call.HttpContext; import org.nuiton.topia.persistence.TopiaNoResultException; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; -import java.util.Date; -import java.util.Locale; import java.util.Map; /** * @author ymartel <martel@codelutin.com> */ -public abstract class CoselmarWebServiceSupport extends WebMotionController implements CoselmarService { +public abstract class CoselmarWebServiceSupport implements CoselmarService { private static final Log log = LogFactory.getLog(CoselmarWebServiceSupport.class); protected static final String AUTHORIZATION_HEADER = "Authorization"; @@ -67,87 +57,6 @@ public abstract class CoselmarWebServiceSupport extends WebMotionController impl this.servicesContext = servicesContext; } - protected CoselmarServicesContext getServicesContext() { - //try to get it from Request context - HttpContext context; - try { - context = getContext(); - } catch (NullPointerException e) { - // not web context ? //XXX ymartel use because unit test on Documents mass import are not in web context ... - context = null; - } - if (context != null) { - CoselmarRestRequestContext requestContext = CoselmarRestRequestContext.getRequestContext(context); - this.servicesContext = requestContext.getServicesContext(); - } - return this.servicesContext; - } - - // Delegate serviceContext // - - protected Date getNow() { - return getServicesContext().getNow(); - } - - protected String getCleanMail(String email) { - return getServicesContext().getCleanMail(email); - } - - protected CoselmarPersistenceContext getPersistenceContext() { - return getServicesContext().getPersistenceContext(); - } - - protected CoselmarServicesConfig getCoselmarServicesConfig() { - return getServicesContext().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 getServicesContext().newService(serviceClass); - } - - // Persistence // - protected DocumentTopiaDao getDocumentDao() { - return getPersistenceContext().getDocumentDao(); - } - - protected CoselmarUserTopiaDao getCoselmarUserDao() { - return getPersistenceContext().getCoselmarUserDao(); - } - - protected CoselmarUserGroupTopiaDao getCoselmarUserGroupDao() { - return getPersistenceContext().getCoselmarUserGroupDao(); - } - - protected QuestionTopiaDao getQuestionDao() { - return getPersistenceContext().getQuestionDao(); - } - - public void commit() { - getPersistenceContext().commit(); - } - - public void rollback() { - getPersistenceContext().rollback(); - } - - /** - * Just get the Authorization header from context - * @return - */ - protected String getAuthorizationHeader() { - return getContext().getHeader(AUTHORIZATION_HEADER); - } - /** * Check the authorization code. * Get the token from the authorization and reconstitute JWT user token. @@ -157,13 +66,13 @@ public abstract class CoselmarWebServiceSupport extends WebMotionController impl * * @throws InvalidCredentialException if token is not valid. * - * @Deprecated since 0.8 : prefer use {@link #checkUserAuthentication(String)} that also check user validity. + * @Deprecated since 0.8 : prefer use {@link #checkUserAuthentication(CoselmarServicesContext, String)} that also check user validity. */ @Deprecated protected UserWebToken checkAuthentication(String authorization) throws InvalidCredentialException { try { - String webSecurityKey = getServicesContext().getCoselmarServicesConfig().getWebSecurityKey(); + String webSecurityKey = CoselmarServicesApplicationContext.getInstance().getApplicationConfig().getWebSecurityKey(); JWTVerifier jwtVerifier = new JWTVerifier(webSecurityKey, "audience"); String token = StringUtils.replace(authorization, "Bearer ", ""); @@ -214,10 +123,10 @@ public abstract class CoselmarWebServiceSupport extends WebMotionController impl * * @throws InvalidCredentialException if token is not valid or if user does not exist. */ - protected CoselmarUser checkUserAuthentication(String authorization) throws InvalidCredentialException { + protected CoselmarUser checkUserAuthentication(CoselmarServicesContext servicesContext, String authorization) throws InvalidCredentialException { try { - String webSecurityKey = getServicesContext().getCoselmarServicesConfig().getWebSecurityKey(); + String webSecurityKey = CoselmarServicesApplicationContext.getInstance().getApplicationConfig().getWebSecurityKey(); JWTVerifier jwtVerifier = new JWTVerifier(webSecurityKey, "audience"); String token = StringUtils.replace(authorization, "Bearer ", ""); @@ -225,8 +134,8 @@ public abstract class CoselmarWebServiceSupport extends WebMotionController impl UserWebToken userWebToken = new UserWebToken(claims); // check user still exist - String userId = getFullUserIdFromShort(userWebToken.getUserId()); - CoselmarUser coselmarUser = getCoselmarUserDao().forTopiaIdEquals(userId).findAny(); + String userId = getFullUserIdFromShort(servicesContext.getPersistenceContext(), userWebToken.getUserId()); + CoselmarUser coselmarUser = servicesContext.getPersistenceContext().getCoselmarUserDao().forTopiaIdEquals(userId).findAny(); return coselmarUser; @@ -277,8 +186,8 @@ public abstract class CoselmarWebServiceSupport extends WebMotionController impl * * @return the complete id, with class FQN. */ - protected String getFullUserIdFromShort(String shortUserId) { - return CoselmarUser.class.getCanonicalName() + getPersistenceContext().getTopiaIdFactory().getSeparator() + shortUserId; + protected String getFullUserIdFromShort(CoselmarPersistenceContext persistenceContext, String shortUserId) { + return CoselmarUser.class.getCanonicalName() + persistenceContext.getTopiaIdFactory().getSeparator() + shortUserId; } /** @@ -289,8 +198,8 @@ public abstract class CoselmarWebServiceSupport extends WebMotionController impl * * @return the complete id, with class FQN. */ - protected String getFullIdFromShort(Class clazz, String shortId) { - return clazz.getCanonicalName() + getPersistenceContext().getTopiaIdFactory().getSeparator() + shortId; + protected String getFullIdFromShort(CoselmarPersistenceContext persistenceContext, Class clazz, String shortId) { + return clazz.getCanonicalName() + persistenceContext.getTopiaIdFactory().getSeparator() + shortId; } /** @@ -300,7 +209,7 @@ public abstract class CoselmarWebServiceSupport extends WebMotionController impl * * @return a light id. */ - protected String getShortIdFromFull(String fullId) { - return getPersistenceContext().getTopiaIdFactory().getRandomPart(fullId); + protected String getShortIdFromFull(CoselmarPersistenceContext persistenceContext, String fullId) { + return persistenceContext.getTopiaIdFactory().getRandomPart(fullId); } } diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/CoselmarTechnicalExceptionMapper.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/CoselmarTechnicalExceptionMapper.java new file mode 100644 index 0000000..55661f8 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/CoselmarTechnicalExceptionMapper.java @@ -0,0 +1,23 @@ +package fr.ifremer.coselmar.services.errors; + +import fr.ifremer.coselmar.exceptions.CoselmarTechnicalException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class CoselmarTechnicalExceptionMapper implements ExceptionMapper<CoselmarTechnicalException> { + + private static final Log log = LogFactory.getLog(CoselmarTechnicalExceptionMapper.class); + + @Override + public Response toResponse(CoselmarTechnicalException exception) { + log.warn("Technical exception", exception); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + } + +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/InvalidCredentialExceptionMapper.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/InvalidCredentialExceptionMapper.java new file mode 100644 index 0000000..a8ec679 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/InvalidCredentialExceptionMapper.java @@ -0,0 +1,22 @@ +package fr.ifremer.coselmar.services.errors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class InvalidCredentialExceptionMapper implements ExceptionMapper<InvalidCredentialException> { + + private static final Log log = LogFactory.getLog(InvalidCredentialExceptionMapper.class); + + @Override + public Response toResponse(InvalidCredentialException exception) { + log.warn("Authorization failed", exception); + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/MailAlreadyExistingExceptionMapper.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/MailAlreadyExistingExceptionMapper.java new file mode 100644 index 0000000..caf198b --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/MailAlreadyExistingExceptionMapper.java @@ -0,0 +1,22 @@ +package fr.ifremer.coselmar.services.errors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class MailAlreadyExistingExceptionMapper implements ExceptionMapper<MailAlreadyExistingException> { + + private static final Log log = LogFactory.getLog(MailAlreadyExistingExceptionMapper.class); + + @Override + public Response toResponse(MailAlreadyExistingException exception) { + log.warn("Asked mail already existing", exception); + return Response.status(Response.Status.CONFLICT).build(); + } + +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/NoResultExceptionMapper.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/NoResultExceptionMapper.java new file mode 100644 index 0000000..c0a4c31 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/NoResultExceptionMapper.java @@ -0,0 +1,22 @@ +package fr.ifremer.coselmar.services.errors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class NoResultExceptionMapper implements ExceptionMapper<NoResultException> { + + private static final Log log = LogFactory.getLog(NoResultExceptionMapper.class); + + @Override + public Response toResponse(NoResultException exception) { + log.warn("No Result found", exception); + return Response.status(Response.Status.NOT_FOUND).build(); + } + +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/TopiaNoResultExceptionMapper.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/TopiaNoResultExceptionMapper.java new file mode 100644 index 0000000..bfd8661 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/TopiaNoResultExceptionMapper.java @@ -0,0 +1,23 @@ +package fr.ifremer.coselmar.services.errors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.topia.persistence.TopiaNoResultException; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class TopiaNoResultExceptionMapper implements ExceptionMapper<TopiaNoResultException> { + + private static final Log log = LogFactory.getLog(TopiaNoResultExceptionMapper.class); + + @Override + public Response toResponse(TopiaNoResultException exception) { + log.warn("No Result found", exception); + return Response.status(Response.Status.NOT_FOUND).build(); + } + +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/UnauthorizedExceptionMapper.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/UnauthorizedExceptionMapper.java new file mode 100644 index 0000000..ee85cf6 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/errors/UnauthorizedExceptionMapper.java @@ -0,0 +1,22 @@ +package fr.ifremer.coselmar.services.errors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class UnauthorizedExceptionMapper implements ExceptionMapper<UnauthorizedException> { + + private static final Log log = LogFactory.getLog(UnauthorizedExceptionMapper.class); + + @Override + public Response toResponse(UnauthorizedException exception) { + log.warn("Unauthorized exception", exception); + return Response.status(Response.Status.FORBIDDEN).build(); + } + +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CORSResponseFilter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CORSResponseFilter.java new file mode 100644 index 0000000..3836659 --- /dev/null +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CORSResponseFilter.java @@ -0,0 +1,46 @@ +package fr.ifremer.coselmar.services.filter; + +/*- + * #%L + * DEPHY-Graph + * %% + * Copyright (C) 2018 - 2019 Inra + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.core.MultivaluedMap; +import java.io.IOException; + +/** + * @author ymartel (martel@codelutin.com) + */ +public class CORSResponseFilter implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) { + + MultivaluedMap<String, Object> headers = responseContext.getHeaders(); + headers.add("Access-Control-Allow-Origin", "*"); + headers.add("Access-Control-Allow-Credentials", "true"); + headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS"); + headers.add("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, Content-Transfer-Encoding"); + } + +} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarRestRequestFilter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarRestRequestFilter.java index 3c75372..38b4ea0 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarRestRequestFilter.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarRestRequestFilter.java @@ -24,110 +24,76 @@ package fr.ifremer.coselmar.services.filter; * #L% */ +import com.google.common.collect.ImmutableList; 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; +import org.jboss.resteasy.spi.ResteasyProviderFactory; -import javax.servlet.http.HttpServletResponse; +import javax.servlet.annotation.WebFilter; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import java.util.List; import java.util.Locale; /** * @author ymartel <martel@codelutin.com> */ -public class CoselmarRestRequestFilter extends WebMotionFilter { +public class CoselmarRestRequestFilter implements ContainerRequestFilter { public static final String REQUEST_PERMISSION_PARAMETER = "permission"; public static final String REQUEST_HEADER_SESSION_TOKEN = "X-Coselmar-Session-Token"; + public static final ImmutableList<Locale> ACCEPT_LANGUAGES = ImmutableList.of(Locale.FRENCH, Locale.ENGLISH); + /** 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) { + @Override + public void filter(ContainerRequestContext context) { Locale locale = getUserLocale(context); CoselmarServicesApplicationContext applicationContext = - CoselmarServicesApplicationContext.getApplicationContext(context.getServletContext()); + CoselmarServicesApplicationContext.getInstance(); CoselmarPersistenceContext persistenceContext = - CoselmarTopiaTransactionFilter.getPersistenceContext(context.getRequest()); + CoselmarTopiaTransactionFilter.getPersistenceContext(context); CoselmarServicesContext serviceContext = applicationContext.newServiceContext(persistenceContext, locale); - CoselmarRestRequestContext requestContext = new CoselmarRestRequestContext(); - requestContext.setServicesContext(serviceContext); - - CoselmarRestRequestContext.setRequestContext(context, requestContext); - - return requestContext; + ResteasyProviderFactory.pushContext(CoselmarServicesContext.class, serviceContext); } - protected Locale getUserLocale(HttpContext context) { - String language = context.getHeader(HttpContext.HEADER_LANGUAGE); + protected Locale getUserLocale(ContainerRequestContext context) { - if (log.isInfoEnabled()) { - log.info("Found Accept-Language: " + language); - } + Locale language = context.getLanguage(); - // 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 (! ACCEPT_LANGUAGES.contains(language)) { - if (language == null) { + List<Locale> languages = context.getAcceptableLanguages(); - language = Locale.FRENCH.getLanguage(); + if (log.isDebugEnabled()) { + log.debug("Found Accept-Language: " + languages.stream() + .map(Locale::getDisplayName) + .reduce((l1, l2) -> l1 + ", " + l2)); + } + + language = languages.stream() + .filter(ACCEPT_LANGUAGES::contains) + .findFirst() + .orElse(ACCEPT_LANGUAGES.get(0)); if (log.isInfoEnabled()) { log.info("Use default language: " + language); } - } - Locale locale = new Locale(language); - return locale; + return language; } } diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarTopiaTransactionFilter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarTopiaTransactionFilter.java index 5ba8f28..046171a 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarTopiaTransactionFilter.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/filter/CoselmarTopiaTransactionFilter.java @@ -35,6 +35,7 @@ import org.nuiton.web.filter.TypedTopiaTransactionFilter; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; +import javax.ws.rs.container.ContainerRequestContext; /** * @author ymartel <martel@codelutin.com> @@ -69,4 +70,10 @@ public class CoselmarTopiaTransactionFilter extends TypedTopiaTransactionFilter< } } + public static CoselmarPersistenceContext getPersistenceContext(ContainerRequestContext context) { + CoselmarPersistenceContext topiaContext = (CoselmarPersistenceContext) + context.getProperty(TOPIA_TRANSACTION_REQUEST_ATTRIBUTE); + return topiaContext; + } + } diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarRestRequestContextInjector.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarRestRequestContextInjector.java deleted file mode 100644 index a568195..0000000 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarRestRequestContextInjector.java +++ /dev/null @@ -1,53 +0,0 @@ -package fr.ifremer.coselmar.services.injector; - -/* - * #%L - * Coselmar :: Rest Services - * $Id:$ - * $HeadURL:$ - * %% - * Copyright (C) 2014 Ifremer, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -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; - -import java.lang.reflect.Type; - -/** - * @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-rest/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarServicesInjector.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarServicesInjector.java deleted file mode 100644 index 5086302..0000000 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/injector/CoselmarServicesInjector.java +++ /dev/null @@ -1,56 +0,0 @@ -package fr.ifremer.coselmar.services.injector; - -/* - * #%L - * Coselmar :: Rest Services - * $Id:$ - * $HeadURL:$ - * %% - * Copyright (C) 2014 Ifremer, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -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; - -import java.lang.reflect.Type; - -/** - * @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-rest/src/main/java/fr/ifremer/coselmar/services/v1/AdminWebService.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/AdminWebService.java index 5686aec..ecd7174 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/AdminWebService.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/AdminWebService.java @@ -26,21 +26,29 @@ package fr.ifremer.coselmar.services.v1; import fr.ifremer.coselmar.beans.DocumentBean; import fr.ifremer.coselmar.beans.QuestionBean; -import fr.ifremer.coselmar.beans.UserWebToken; import fr.ifremer.coselmar.converter.BeanEntityConverter; import fr.ifremer.coselmar.exceptions.CoselmarTechnicalException; +import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; +import fr.ifremer.coselmar.persistence.entity.CoselmarUser; import fr.ifremer.coselmar.persistence.entity.CoselmarUserRole; import fr.ifremer.coselmar.persistence.entity.Document; import fr.ifremer.coselmar.persistence.entity.Question; +import fr.ifremer.coselmar.services.CoselmarServicesContext; import fr.ifremer.coselmar.services.CoselmarWebServiceSupport; import fr.ifremer.coselmar.services.errors.InvalidCredentialException; import fr.ifremer.coselmar.services.errors.UnauthorizedException; import fr.ifremer.coselmar.services.indexation.DocumentsIndexationService; import fr.ifremer.coselmar.services.indexation.QuestionsIndexationService; import fr.ifremer.coselmar.services.indexation.TikaUtils; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; +import javax.ws.rs.Consumes; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; import java.io.IOException; import java.util.List; @@ -49,18 +57,24 @@ import static org.apache.commons.logging.LogFactory.getLog; /** * @author ymartel <martel@codelutin.com> */ +@Path("") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) public class AdminWebService extends CoselmarWebServiceSupport { private static final Log log = getLog(AdminWebService.class); - public void refreshLuceneIndex() throws UnauthorizedException, InvalidCredentialException { + @POST + @Path("/v1/admin/lucene/index") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public void refreshLuceneIndex(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization) throws UnauthorizedException, InvalidCredentialException { // Check authentication - String authorization = getContext().getHeader("Authorization"); - UserWebToken userWebToken = checkAuthentication(authorization); + CoselmarUser userWeb = checkUserAuthentication(servicesContext, authorization); - // Who is allowed here ? Admin and user himself - if (!StringUtils.equals(userWebToken.getRole(), CoselmarUserRole.ADMIN.name())) { + // Who is allowed here ? Admin only + if (userWeb.getRole() != CoselmarUserRole.ADMIN) { if (log.isDebugEnabled()) { String message = String.format("A non admin user try to refresh lucene index."); log.debug(message); @@ -69,16 +83,17 @@ public class AdminWebService extends CoselmarWebServiceSupport { } - QuestionsIndexationService questionsIndexationService = getServicesContext().newService(QuestionsIndexationService.class); + QuestionsIndexationService questionsIndexationService = servicesContext.newService(QuestionsIndexationService.class); try { - getServicesContext().getLuceneUtils().clearIndex(); - refreshDocumentsIndex(); + servicesContext.getLuceneUtils().clearIndex(); + refreshDocumentsIndex(servicesContext); // Get all questions - List<Question> questions = getQuestionDao().findAll(); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + List<Question> questions = persistenceContext.getQuestionDao().findAll(); for (Question question : questions) { - QuestionBean questionBean = BeanEntityConverter.toLightBean(getPersistenceContext().getTopiaIdFactory(), question); + QuestionBean questionBean = BeanEntityConverter.toLightBean(persistenceContext.getTopiaIdFactory(), question); questionsIndexationService.indexQuestion(questionBean); } @@ -94,23 +109,24 @@ public class AdminWebService extends CoselmarWebServiceSupport { } } - protected void refreshDocumentsIndex() throws IOException { - DocumentsIndexationService documentsIndexationService = getServicesContext().newService(DocumentsIndexationService.class); + protected void refreshDocumentsIndex(CoselmarServicesContext servicesContext) throws IOException { + DocumentsIndexationService documentsIndexationService = servicesContext.newService(DocumentsIndexationService.class); documentsIndexationService.cleanIndex(); // get All documents - List<Document> documents = getDocumentDao().findAll(); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + List<Document> documents = persistenceContext.getDocumentDao().findAll(); for (Document document : documents) { - DocumentBean documentBean = BeanEntityConverter.toBean(getPersistenceContext().getTopiaIdFactory(), document); + DocumentBean documentBean = BeanEntityConverter.toBean(persistenceContext.getTopiaIdFactory(), document); if (document.isWithFile()) { // Refresh file information String fileContent = TikaUtils.getFileContent(document.getFilePath()); documentsIndexationService.indexDocument(documentBean, fileContent); // Refresh database content document.setFileContent(fileContent); - getDocumentDao().update(document); + persistenceContext.getDocumentDao().update(document); } } - commit(); + persistenceContext.commit(); } } diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java index bac184f..b84ad05 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java @@ -41,12 +41,14 @@ import fr.ifremer.coselmar.beans.UserBean; import fr.ifremer.coselmar.beans.UserWebToken; import fr.ifremer.coselmar.converter.BeanEntityConverter; import fr.ifremer.coselmar.exceptions.CoselmarTechnicalException; +import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; import fr.ifremer.coselmar.persistence.entity.CoselmarUser; import fr.ifremer.coselmar.persistence.entity.CoselmarUserGroup; import fr.ifremer.coselmar.persistence.entity.CoselmarUserRole; import fr.ifremer.coselmar.persistence.entity.Document; import fr.ifremer.coselmar.persistence.entity.Privacy; import fr.ifremer.coselmar.persistence.entity.Question; +import fr.ifremer.coselmar.services.CoselmarServicesContext; import fr.ifremer.coselmar.services.CoselmarWebServiceSupport; import fr.ifremer.coselmar.services.errors.InvalidCredentialException; import fr.ifremer.coselmar.services.errors.NoResultException; @@ -58,21 +60,30 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.lucene.queryparser.classic.ParseException; -import org.debux.webmotion.server.call.UploadFile; -import org.debux.webmotion.server.render.Render; +import org.jboss.resteasy.plugins.providers.multipart.InputPart; +import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput; import org.nuiton.csv.Import; import org.nuiton.csv.ImportRuntimeException; import org.nuiton.topia.persistence.TopiaNoResultException; import org.nuiton.util.DateUtil; import org.nuiton.util.pagination.PaginationResult; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; @@ -81,6 +92,8 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -89,6 +102,9 @@ import static org.apache.commons.logging.LogFactory.getLog; /** * @author ymartel <martel@codelutin.com> */ +@Path("") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) public class DocumentsWebService extends CoselmarWebServiceSupport { private static final Log log = getLog(DocumentsWebService.class); @@ -96,7 +112,9 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { public static final List<String> DOCUMENT_CREATE_ALLOWED_USER_ROLES = Lists.newArrayList(CoselmarUserRole.ADMIN.name(), CoselmarUserRole.SUPERVISOR.name(), CoselmarUserRole.EXPERT.name()); - /** Kind of admin role **/ + /** + * Kind of admin role + **/ public static final List<String> DOCUMENT_SUPER_USER_ROLES = Lists.newArrayList(CoselmarUserRole.ADMIN.name(), CoselmarUserRole.SUPERVISOR.name()); @@ -108,23 +126,27 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { ); protected static final String DESCRIPTION_CSV_FILE_NAME = "description.csv"; - public DocumentBean getDocument(String documentId) throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/documents/{documentId}") + public DocumentBean getDocument(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("documentId") String documentId) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); // reconstitute full id - String fullId = getDocumentFullId(documentId); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + String fullId = getDocumentFullId(persistenceContext, documentId); - Document document = getDocumentDao().forTopiaIdEquals(fullId).findUnique(); + Document document = persistenceContext.getDocumentDao().forTopiaIdEquals(fullId).findUnique(); // If document if public, only admin, supervisor and expert could view it // If document if private, only admin, supervisor and owner could view it if (!isAllowedToAccessDocument(currentUser, document)) { String message = String.format("User %s %s ('%s') try to access to document '%s'", - currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(currentUser.getTopiaId()), documentId); + currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(persistenceContext, currentUser.getTopiaId()), documentId); if (log.isWarnEnabled()) { log.warn(message); } @@ -132,18 +154,18 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { } - DocumentBean documentBean = BeanEntityConverter.toBean(getPersistenceContext().getTopiaIdFactory(), document); + DocumentBean documentBean = BeanEntityConverter.toBean(persistenceContext.getTopiaIdFactory(), document); // Manage related Question - List<Question> relatedQuestions = getQuestionDao().forRelatedDocumentsContains(document).findAll(); + List<Question> relatedQuestions = persistenceContext.getQuestionDao().forRelatedDocumentsContains(document).findAll(); for (Question relatedQuestion : relatedQuestions) { - QuestionBean questionBean = BeanEntityConverter.toLightBean(getPersistenceContext().getTopiaIdFactory(), relatedQuestion); + QuestionBean questionBean = BeanEntityConverter.toLightBean(persistenceContext.getTopiaIdFactory(), relatedQuestion); documentBean.addRelatedQuestion(questionBean); } // Manage related Question - List<Question> relatedQuestionsAsClosing = getQuestionDao().forClosingDocumentsContains(document).findAll(); + List<Question> relatedQuestionsAsClosing = persistenceContext.getQuestionDao().forClosingDocumentsContains(document).findAll(); for (Question relatedQuestion : relatedQuestionsAsClosing) { - QuestionBean questionBean = BeanEntityConverter.toLightBean(getPersistenceContext().getTopiaIdFactory(), relatedQuestion); + QuestionBean questionBean = BeanEntityConverter.toLightBean(persistenceContext.getTopiaIdFactory(), relatedQuestion); documentBean.addRelatedQuestion(questionBean); } @@ -154,7 +176,7 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { if (StringUtils.equalsIgnoreCase(fullId, usersGroup.getName())) { Set<CoselmarUser> members = usersGroup.getMembers(); for (CoselmarUser member : members) { - String userLightId = getPersistenceContext().getTopiaIdFactory().getRandomPart(member.getTopiaId()); + String userLightId = getShortIdFromFull(persistenceContext, member.getTopiaId()); UserBean userBean = BeanEntityConverter.toBean(userLightId, member); documentBean.addAuthorizedUser(userBean); } @@ -166,18 +188,25 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { return documentBean; } - public List<DocumentBean> getDocuments(DocumentSearchBean searchBean) throws InvalidCredentialException { + @GET + @Path("/v1/documents") + public List<DocumentBean> getDocuments(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @QueryParam("searchBean") DocumentSearchBean searchBean) throws InvalidCredentialException { - PaginationResult<DocumentBean> paginatedDocuments = getPaginatedDocuments(searchBean); + PaginationResult<DocumentBean> paginatedDocuments = getPaginatedDocuments(servicesContext, authorization, searchBean); return paginatedDocuments.getElements(); } - public PaginationResult<DocumentBean> getPaginatedDocuments(DocumentSearchBean searchBean) throws InvalidCredentialException { + @GET + @Path("/v2/documents") + public PaginationResult<DocumentBean> getPaginatedDocuments(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @QueryParam("searchBean") DocumentSearchBean searchBean) throws InvalidCredentialException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); CoselmarUserRole currentUserRole = currentUser.getRole(); @@ -221,17 +250,18 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { PaginationResult<Document> paginatedDocuments; // Admin and Supervisor can see all documents (public, private and restricted) + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); if (Lists.newArrayList(CoselmarUserRole.ADMIN, CoselmarUserRole.SUPERVISOR).contains(currentUserRole)) { List<String> searchKeywords = searchBean.getFullTextSearch(); if (searchKeywords != null && !searchKeywords.isEmpty()) { - DocumentsIndexationService documentsIndexationService = getServicesContext().newService(DocumentsIndexationService.class); + DocumentsIndexationService documentsIndexationService = servicesContext.newService(DocumentsIndexationService.class); try { List<String> documentIds = documentsIndexationService.searchDocuments(searchKeywords); - List<String> documentFullIds = getDocumentsFullId(documentIds); + List<String> documentFullIds = getDocumentsFullId(persistenceContext, documentIds); - Long count = getDocumentDao().forTopiaIdIn(documentFullIds).count(); - List<Document> documentList = getDocumentDao().forTopiaIdIn(documentFullIds).find(searchExample.getPaginationParameter()); + Long count = persistenceContext.getDocumentDao().forTopiaIdIn(documentFullIds).count(); + List<Document> documentList = persistenceContext.getDocumentDao().forTopiaIdIn(documentFullIds).find(searchExample.getPaginationParameter()); paginatedDocuments = PaginationResult.of(documentList, count, searchExample.getPaginationParameter()); @@ -239,27 +269,27 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { if (log.isErrorEnabled()) { log.error("Unable to search by lucene, make search directly in database", e); } - paginatedDocuments = getDocumentDao().findPaginatedContainingAllKeywords(searchKeywords, searchExample.getPaginationParameter()); + paginatedDocuments = persistenceContext.getDocumentDao().findPaginatedContainingAllKeywords(searchKeywords, searchExample.getPaginationParameter()); } } else { - paginatedDocuments = getDocumentDao().findAllByExample(null, searchExample); + paginatedDocuments = persistenceContext.getDocumentDao().findAllByExample(null, searchExample); } } else { //Other can only see public, his own private and restricted for which he is allowed - paginatedDocuments = getDocumentDao().findAllByExample(currentUser, searchExample); + paginatedDocuments = persistenceContext.getDocumentDao().findAllByExample(currentUser, searchExample); } List<DocumentBean> documentBeans = new ArrayList<>(paginatedDocuments.getElements().size()); for (Document document : paginatedDocuments.getElements()) { - DocumentBean documentBean = BeanEntityConverter.toBean(getPersistenceContext().getTopiaIdFactory(), document); + DocumentBean documentBean = BeanEntityConverter.toBean(persistenceContext.getTopiaIdFactory(), document); // Manage related Question - long relatedQuestions = getQuestionDao().forRelatedDocumentsContains(document).count(); + long relatedQuestions = persistenceContext.getQuestionDao().forRelatedDocumentsContains(document).count(); // Don't forget use as closing documents - long relatedQuestionsAsClosing = getQuestionDao().forClosingDocumentsContains(document).count(); + long relatedQuestionsAsClosing = persistenceContext.getQuestionDao().forClosingDocumentsContains(document).count(); documentBean.setNbRelatedQuestions((int) (relatedQuestions + relatedQuestionsAsClosing)); @@ -270,11 +300,14 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { return result; } - public List<String> getSearchBibliography(DocumentSearchBean searchBean) throws InvalidCredentialException { + @GET + @Path("/v2/documents/citations") + public List<String> getSearchBibliography(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @QueryParam("searchBean") DocumentSearchBean searchBean) throws InvalidCredentialException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); CoselmarUserRole currentUserRole = currentUser.getRole(); @@ -315,31 +348,32 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { List<String> citations; // Admin and Supervisor can see all documents (public, private and restricted) + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); if (Lists.newArrayList(CoselmarUserRole.ADMIN, CoselmarUserRole.SUPERVISOR).contains(currentUserRole)) { List<String> searchKeywords = searchBean.getFullTextSearch(); if (searchKeywords != null && !searchKeywords.isEmpty()) { - DocumentsIndexationService documentsIndexationService = getServicesContext().newService(DocumentsIndexationService.class); + DocumentsIndexationService documentsIndexationService = servicesContext.newService(DocumentsIndexationService.class); try { List<String> documentIds = documentsIndexationService.searchDocuments(searchKeywords); - List<String> documentFullIds = getDocumentsFullId(documentIds); + List<String> documentFullIds = getDocumentsFullId(persistenceContext, documentIds); - citations = getDocumentDao().findCitationsByDocumentIds(documentFullIds); + citations = persistenceContext.getDocumentDao().findCitationsByDocumentIds(documentFullIds); } catch (IOException | ParseException e) { if (log.isErrorEnabled()) { log.error("Unable to search by lucene, make search directly in database", e); } - citations = getDocumentDao().findCitationsByDocumentFromKeywords(searchKeywords); + citations = persistenceContext.getDocumentDao().findCitationsByDocumentFromKeywords(searchKeywords); } } else { - citations = getDocumentDao().findCitationsByDocumentExample(null, searchExample); + citations = persistenceContext.getDocumentDao().findCitationsByDocumentExample(null, searchExample); } } else { //Other can only see public, his own private and restricted for which he is allowed - citations = getDocumentDao().findCitationsByDocumentExample(currentUser, searchExample); + citations = persistenceContext.getDocumentDao().findCitationsByDocumentExample(currentUser, searchExample); } Iterables.removeIf(citations, new Predicate<String>() { @@ -352,10 +386,15 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { return citations; } - public DocumentBean addDocument(DocumentBean document, UploadFile uploadFile) throws InvalidCredentialException, UnauthorizedException { + @POST + @Path("/v1/documents") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public DocumentBean addDocument(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + DocumentBean document, + MultipartFormDataInput uploadFile) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); UserWebToken userWebToken = checkAuthentication(authorization); // Only Expert or Supervisor can add document @@ -372,11 +411,12 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { Preconditions.checkNotNull(document); // retrieve user who will be assigned as document owner - String fullId = getFullUserIdFromShort(userWebToken.getUserId()); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + String fullId = getFullUserIdFromShort(persistenceContext, userWebToken.getUserId()); CoselmarUser owner; try { - owner = getCoselmarUserDao().forTopiaIdEquals(fullId).findUnique(); + owner = persistenceContext.getCoselmarUserDao().forTopiaIdEquals(fullId).findUnique(); } catch (TopiaNoResultException tnre) { // Should not happened, cause user are not really deleted String message = String.format("Seems that logged user ('%s') does not exist anymore.", fullId); @@ -388,34 +428,40 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { FileInfos fileInfos = null; if (uploadFile != null) { - fileInfos = manageDocumentFile(uploadFile, owner); + fileInfos = manageDocumentFile(servicesContext, uploadFile, owner); } - DocumentBean result = createDocument(document, fileInfos, owner); + DocumentBean result = createDocument(servicesContext, document, fileInfos, owner); - commit(); + persistenceContext.commit(); return result; } - public void addDocumentFile(String documentId, UploadFile uploadFile) throws InvalidCredentialException, UnauthorizedException { + @POST + @Path("/v1/documents/{documentId}/file") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public void addDocumentFile(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("documentId") String documentId, + MultipartFormDataInput uploadFile) throws InvalidCredentialException, UnauthorizedException { Preconditions.checkNotNull(documentId); Preconditions.checkNotNull(uploadFile); // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); - String documentFullId = getFullIdFromShort(Document.class, documentId); - Document documentEntity = getDocumentDao().forTopiaIdEquals(documentFullId).findAny(); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + String documentFullId = getFullIdFromShort(persistenceContext, Document.class, documentId); + Document documentEntity = persistenceContext.getDocumentDao().forTopiaIdEquals(documentFullId).findAny(); // Only Owner Expert or Supervisor/Admin can add document file if (!DOCUMENT_SUPER_USER_ROLES.contains(currentUser.getRole().name()) && documentEntity.getOwner() != currentUser) { String message = String.format("User %s %s ('%s') is not allowed to add document file", - currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(currentUser.getTopiaId())); + currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(persistenceContext, currentUser.getTopiaId())); if (log.isWarnEnabled()) { log.warn(message); } @@ -424,7 +470,7 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { // Get owner to place correctly the file CoselmarUser owner = documentEntity.getOwner(); - FileInfos fileInfos = manageDocumentFile(uploadFile, owner); + FileInfos fileInfos = manageDocumentFile(servicesContext, uploadFile, owner); String filePath = fileInfos.getFinalFilePath(); String contentType = fileInfos.getMimeType(); // Read file content @@ -439,13 +485,13 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { documentEntity.setWithFile(true); documentEntity.setMimeType(contentType); documentEntity.setFilePath(filePath); - documentEntity.setFileName(uploadFile.getName()); + documentEntity.setFileName(fileInfos.getFileName()); documentEntity.setFileContent(fileContent); // Should update document index information to put the file - DocumentBean documentBean = BeanEntityConverter.toBean(getPersistenceContext().getTopiaIdFactory(), documentEntity); + DocumentBean documentBean = BeanEntityConverter.toBean(persistenceContext.getTopiaIdFactory(), documentEntity); - DocumentsIndexationService documentsIndexationService = getServicesContext().newService(DocumentsIndexationService.class); + DocumentsIndexationService documentsIndexationService = servicesContext.newService(DocumentsIndexationService.class); try { documentsIndexationService.updateDocument(documentBean, fileContent); if (log.isDebugEnabled()) { @@ -458,17 +504,23 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { } } - commit(); + persistenceContext.commit(); } - public Render getDocumentFile(String documentId) throws NoResultException { + @GET + @Path("/v1/documents/{documentId}/file") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response getDocumentFile(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("documentId") String documentId) throws NoResultException { // reconstitute full id - String fullId =getDocumentFullId(documentId); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + String fullId = getDocumentFullId(persistenceContext, documentId); - Document document = getDocumentDao().forTopiaIdEquals(fullId).findUnique(); + Document document = persistenceContext.getDocumentDao().forTopiaIdEquals(fullId).findUnique(); //TODO ymartel 20141103 : manage file owner ? // Get file attached to document @@ -480,36 +532,32 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { String fileName = StringUtils.isNotBlank(document.getFileName()) ? document.getFileName() : document.getName(); String fileMimeType = document.getMimeType(); - try { - InputStream fileStream = new FileInputStream(documentFile); - return renderDownload(fileStream, fileName, fileMimeType); - - } catch (FileNotFoundException e) { - if (log.isErrorEnabled()) { - String message = String.format("Unable to retrieve file %s", fileName); - log.error(message, e); - } - throw new NoResultException("File does not exist"); - } + Response.ResponseBuilder ok = Response.ok(documentFile, fileMimeType); + ok.header("Content-Disposition", "attachment; filename=\"" + fileName + "\""); + return ok.build(); } - public void saveDocument(DocumentBean document) throws InvalidCredentialException, UnauthorizedException { + @POST + @Path("/v1/documents/{documentId}") + public void saveDocument(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + DocumentBean document) throws InvalidCredentialException, UnauthorizedException { Preconditions.checkNotNull(document); Preconditions.checkNotNull(document.getId()); // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); - String documentId = getDocumentFullId(document.getId()); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + String documentId = getDocumentFullId(persistenceContext, document.getId()); - Document documentEntity = getDocumentDao().forTopiaIdEquals(documentId).findUnique(); + Document documentEntity = persistenceContext.getDocumentDao().forTopiaIdEquals(documentId).findUnique(); if (!isAllowedToAccessDocument(currentUser, documentEntity)) { String message = String.format("User %s %s ('%s') try to modify document '%s'", - currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(currentUser.getTopiaId()), documentId); + currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(persistenceContext, currentUser.getTopiaId()), documentId); if (log.isWarnEnabled()) { log.warn(message); } @@ -517,7 +565,7 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { } - boolean isUsedByQuestions = getQuestionDao().forRelatedDocumentsContains(documentEntity).exists(); + boolean isUsedByQuestions = persistenceContext.getQuestionDao().forRelatedDocumentsContains(documentEntity).exists(); if (isUsedByQuestions && currentUser.getRole() != CoselmarUserRole.ADMIN) { String message = "Document is used by some questions, cannot be modified."; if (log.isWarnEnabled()) { @@ -534,7 +582,7 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { // Manage privacy : if restricted, create an UserGroup with authorized users if (StringUtils.equals(Privacy.RESTRICTED.name(), newPrivacy)) { Set<UserBean> authorizedUsers = document.getAuthorizedUsers(); - Set<CoselmarUser> coselmarUsers = retrieveUsers(authorizedUsers); + Set<CoselmarUser> coselmarUsers = retrieveUsers(persistenceContext, authorizedUsers); Set<CoselmarUserGroup> restrictedList = documentEntity.getRestrictedList(); CoselmarUserGroup restrictedUsers = null; @@ -550,7 +598,7 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { } } if (restrictedUsers == null) { - restrictedUsers = getCoselmarUserGroupDao().create(); + restrictedUsers = persistenceContext.getCoselmarUserGroupDao().create(); restrictedUsers.setName(documentEntity.getTopiaId()); } @@ -570,7 +618,7 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { // Remove group from document, and delete it ! if (restrictedUsers != null) { documentEntity.removeRestrictedList(restrictedUsers); - getCoselmarUserGroupDao().delete(restrictedUsers); + persistenceContext.getCoselmarUserGroupDao().delete(restrictedUsers); } } @@ -604,14 +652,14 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { documentEntity.setCitation(document.getCitation()); - commit(); + persistenceContext.commit(); // Update index information for this document - DocumentBean result = BeanEntityConverter.toBean(getPersistenceContext().getTopiaIdFactory(), documentEntity); + DocumentBean result = BeanEntityConverter.toBean(persistenceContext.getTopiaIdFactory(), documentEntity); - DocumentsIndexationService documentsIndexationService = getServicesContext().newService(DocumentsIndexationService.class); + DocumentsIndexationService documentsIndexationService = servicesContext.newService(DocumentsIndexationService.class); try { - documentsIndexationService.indexDocument(result, null); // no document file for the moment here + documentsIndexationService.indexDocument(result, null); // no document file for the moment here if (log.isDebugEnabled()) { String message = String.format("Document '%s' was updated in index", document.getName()); log.debug(message); @@ -624,22 +672,26 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { } - public void deleteDocument(String documentId) throws InvalidCredentialException, UnauthorizedException { + @DELETE + @Path("/v1/documents/{documentId}") + public void deleteDocument(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("documentId") String documentId) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); // reconstitute full id - String fullId = getDocumentFullId(documentId); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + String fullId = getDocumentFullId(persistenceContext, documentId); - Document document = getDocumentDao().forTopiaIdEquals(fullId).findUnique(); + Document document = persistenceContext.getDocumentDao().forTopiaIdEquals(fullId).findUnique(); if (!DOCUMENT_SUPER_USER_ROLES.contains(currentUser.getRole().name()) && document.getOwner() != currentUser) { String message = String.format("User %s %s ('%s') try to delete document '%s'", - currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(currentUser.getTopiaId()), documentId); + currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(persistenceContext, currentUser.getTopiaId()), documentId); if (log.isWarnEnabled()) { log.warn(message); } @@ -650,12 +702,12 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { // Delete physical file deleteAttachedFile(document); - getDocumentDao().delete(document); + persistenceContext.getDocumentDao().delete(document); - commit(); + persistenceContext.commit(); //Remove index entry - DocumentsIndexationService documentsIndexationService = getServicesContext().newService(DocumentsIndexationService.class); + DocumentsIndexationService documentsIndexationService = servicesContext.newService(DocumentsIndexationService.class); try { documentsIndexationService.deleteDocument(documentId); if (log.isDebugEnabled()) { @@ -669,38 +721,49 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { } } - public List<String> getKeywords() throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/documents/keywords") + public List<String> getKeywords(@Context CoselmarServicesContext servicesContext) throws InvalidCredentialException, UnauthorizedException { - List<String> themes = getDocumentDao().findAllKeywords(); + List<String> themes = servicesContext.getPersistenceContext().getDocumentDao().findAllKeywords(); return themes; } - public List<String> getTypes() throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/documents/types") + public List<String> getTypes(@Context CoselmarServicesContext servicesContext) throws InvalidCredentialException, UnauthorizedException { - List<String> types = getDocumentDao().findAllTypes(); + List<String> types = servicesContext.getPersistenceContext().getDocumentDao().findAllTypes(); return types; } - public MassiveDocumentsImportResult uploadZipDocuments(UploadFile uploadFile) throws InvalidCredentialException, UnauthorizedException { + @POST + @Path("/v1/admin/documents/zip") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public MassiveDocumentsImportResult uploadZipDocuments(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + MultipartFormDataInput uploadFile) throws InvalidCredentialException, UnauthorizedException { Preconditions.checkNotNull(uploadFile); // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); // Only Supervisor/Admin can add Zip documents if (!DOCUMENT_SUPER_USER_ROLES.contains(currentUser.getRole().name())) { String message = String.format("User %s %s ('%s') is not allowed to upload mass document files", - currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(currentUser.getTopiaId())); + currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(servicesContext.getPersistenceContext(), currentUser.getTopiaId())); if (log.isWarnEnabled()) { log.warn(message); } throw new UnauthorizedException(message); } - return importFromZip(uploadFile.getFile(), currentUser); + + File file = getFileFromMultipart(uploadFile, "uploadFile", "importFile_" + servicesContext.getNow().getTime() + ".zip"); + + return importFromZip(servicesContext, file, currentUser); } @@ -714,10 +777,10 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { * * @return a DocumentBean with all created {@link Document} data. */ - protected DocumentBean createDocument(DocumentBean documentBean, FileInfos fileInfos, CoselmarUser owner) { + protected DocumentBean createDocument(CoselmarServicesContext servicesContext, DocumentBean documentBean, FileInfos fileInfos, CoselmarUser owner) { // Document Metadata - Document documentEntity = createDocumentMetadataFromBean(documentBean, owner); + Document documentEntity = createDocumentMetadataFromBean(servicesContext, documentBean, owner); // If document has a file, manage it ! String fileContent = ""; @@ -739,10 +802,10 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { documentEntity.setWithFile(false); } - DocumentBean result = BeanEntityConverter.toBean(getPersistenceContext().getTopiaIdFactory(), documentEntity); + DocumentBean result = BeanEntityConverter.toBean(servicesContext.getPersistenceContext().getTopiaIdFactory(), documentEntity); // Indexation job - DocumentsIndexationService documentsIndexationService = getServicesContext().newService(DocumentsIndexationService.class); + DocumentsIndexationService documentsIndexationService = servicesContext.newService(DocumentsIndexationService.class); try { documentsIndexationService.indexDocument(result, fileContent); if (log.isDebugEnabled()) { @@ -762,11 +825,12 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { * This also manage owner and restriction but <strong>does not manage</strong> attached file part. * No commit are done here. */ - public Document createDocumentMetadataFromBean(DocumentBean documentBean, CoselmarUser owner) { + public Document createDocumentMetadataFromBean(CoselmarServicesContext servicesContext, DocumentBean documentBean, CoselmarUser owner) { Preconditions.checkNotNull(documentBean); // Document Metadata - Document document = getDocumentDao().create(); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + Document document = persistenceContext.getDocumentDao().create(); document.setOwner(owner); @@ -778,8 +842,8 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { // Manage privacy : if restricted, create an UserGroup with authorized users if (StringUtils.equals(Privacy.RESTRICTED.name(), privacy)) { Set<UserBean> authorizedUsers = documentBean.getAuthorizedUsers(); - Set<CoselmarUser> coselmarUsers = retrieveUsers(authorizedUsers); - CoselmarUserGroup restrictedUsers = getCoselmarUserGroupDao().create(); + Set<CoselmarUser> coselmarUsers = retrieveUsers(persistenceContext, authorizedUsers); + CoselmarUserGroup restrictedUsers = persistenceContext.getCoselmarUserGroupDao().create(); restrictedUsers.setName(document.getTopiaId()); restrictedUsers.addAllMembers(coselmarUsers); @@ -823,55 +887,64 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { * * @return the upload file Metadata */ - protected FileInfos manageDocumentFile(UploadFile uploadFile, CoselmarUser owner) { + protected FileInfos manageDocumentFile(CoselmarServicesContext servicesContext, MultipartFormDataInput uploadFile, CoselmarUser owner) { Preconditions.checkNotNull(uploadFile); - // Document File - String fileName = uploadFile.getName(); - File uploadedFile = uploadFile.getFile(); - String contentType = uploadFile.getContentType(); + try { + // Document File + InputStream in = uploadFile.getFormDataPart("uploadFile", InputStream.class, null); + InputPart inputPart = uploadFile.getFormDataMap().get("uploadFile").get(0); + + String contentDisposition = inputPart.getHeaders().get("Content-Disposition").get(0); + Pattern FilenamePattern = Pattern.compile("filename=\"(.*)\""); + Matcher matcher = FilenamePattern.matcher(contentDisposition); + String fileName = "no-name-" + servicesContext.getNow().getTime() + "-" + owner.getName() + "_" + owner.getFirstname(); + if (matcher.find()) { + fileName = matcher.group(1); + } - if (log.isDebugEnabled()) { - String message = String.format("File name : %s, content-type : %s", fileName, contentType); - log.debug(message); - } + String contentType = inputPart.getHeaders().get("Content-Type").get(0); + + if (log.isDebugEnabled()) { + String message = String.format("File name : %s, content-type : %s", fileName, contentType); + log.debug(message); + } - // put the document in the good directory - String filePath = getDocumentFileDestPath(owner, fileName); + // put the document in the good directory + String filePath = getDocumentFileDestPath(servicesContext, owner, fileName); + File uploadedFile = new File(filePath); + Files.copy(in, uploadedFile.toPath()); + + FileInfos fileInfos = new FileInfos(); + fileInfos.setFileName(fileName); + fileInfos.setMimeType(contentType); + fileInfos.setFinalFilePath(uploadedFile.getAbsolutePath()); + return fileInfos; - File destFile = new File(filePath); - try { - FileUtils.moveFile(uploadedFile, destFile); } catch (IOException e) { if (log.isErrorEnabled()) { log.error("error during File transfer", e); } throw new CoselmarTechnicalException("Internal error during file transfer", e); } - - FileInfos fileInfos = new FileInfos(); - fileInfos.setFileName(fileName); - fileInfos.setMimeType(contentType); - fileInfos.setFinalFilePath(destFile.getAbsolutePath()); - return fileInfos; } - protected String getDocumentFileDestPath(CoselmarUser owner, String fileName) { - String userPath = getUserDocumentPath(owner); + protected String getDocumentFileDestPath(CoselmarServicesContext servicesContext, CoselmarUser owner, String fileName) { + String userPath = getUserDocumentPath(servicesContext, owner); - String storageFileName = getFileStorageName(fileName); + String storageFileName = getFileStorageName(servicesContext, fileName); return userPath + File.separator + storageFileName; } - protected String getFileStorageName(String fileName) { - Date now = getNow(); + protected String getFileStorageName(CoselmarServicesContext servicesContext, String fileName) { + Date now = servicesContext.getNow(); String formattedDay = DateUtil.formatDate(now, "yyyyMMddHHmm"); String prefix = formattedDay + "-"; return prefix + fileName; } - protected String getUserDocumentPath(CoselmarUser user) { - File dataDirectory = getCoselmarServicesConfig().getDataDirectory(); + protected String getUserDocumentPath(CoselmarServicesContext servicesContext, CoselmarUser user) { + File dataDirectory = servicesContext.getCoselmarServicesConfig().getDataDirectory(); String absolutePath = dataDirectory.getAbsolutePath(); String userFolder = StringUtils.replaceChars(user.getFirstname() + "-" + user.getName(), " ", "_"); String userPath = absolutePath + File.separator + userFolder; @@ -882,10 +955,9 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { * Check if an user can access to a document metadata, according to its * privacy settings and the user grant. * - * @param user : Current User, - * containing {@link fr.ifremer.coselmar.persistence.entity.CoselmarUserRole} as String - * @param document : the document user trying to access. - * + * @param user : Current User, + * containing {@link fr.ifremer.coselmar.persistence.entity.CoselmarUserRole} as String + * @param document : the document user trying to access. * @return true is user can access, false else. */ protected boolean isAllowedToAccessDocument(CoselmarUser user, Document document) { @@ -901,7 +973,7 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { if (document.getPrivacy() == Privacy.PUBLIC) { isAuthorized = DOCUMENT_VIEW_ALLOWED_USER_ROLES.contains(viewerRole); - // For Private : only admin/supervisor/owner can access + // For Private : only admin/supervisor/owner can access } else if (document.getPrivacy() == Privacy.PRIVATE) { CoselmarUser documentOwner = document.getOwner(); boolean isOwner = StringUtils.equals(documentOwner.getTopiaId(), user.getTopiaId()); @@ -920,16 +992,16 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { return isAuthorized; } - protected String getDocumentFullId(String documentId) { - return Document.class.getCanonicalName() + getPersistenceContext().getTopiaIdFactory().getSeparator() + documentId; + protected String getDocumentFullId(CoselmarPersistenceContext persistenceContext, String documentId) { + return getFullIdFromShort(persistenceContext, Document.class, documentId); } - protected List<String> getDocumentsFullId(List<String> documentShortIds) { + protected List<String> getDocumentsFullId(CoselmarPersistenceContext persistenceContext, List<String> documentShortIds) { Function<String, String> getFullIds = new Function<String, String>() { @Override public String apply(String shortId) { - return getDocumentFullId(shortId); + return getDocumentFullId(persistenceContext, shortId); } }; @@ -952,21 +1024,21 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { } } - protected Set<CoselmarUser> retrieveUsers(Collection<UserBean> userBeans) { + protected Set<CoselmarUser> retrieveUsers(CoselmarPersistenceContext persistenceContext, Collection<UserBean> userBeans) { Function<UserBean, String> getIds = new Function<UserBean, String>() { @Override public String apply(UserBean userBean) { - return getFullIdFromShort(CoselmarUser.class, userBean.getId()); + return getFullIdFromShort(persistenceContext, CoselmarUser.class, userBean.getId()); } }; Collection<String> userIds = Collections2.transform(userBeans, getIds); - List<CoselmarUser> coselmarUsers = getCoselmarUserDao().forTopiaIdIn(userIds).findAll(); + List<CoselmarUser> coselmarUsers = persistenceContext.getCoselmarUserDao().forTopiaIdIn(userIds).findAll(); return new HashSet<>(coselmarUsers); } - protected MassiveDocumentsImportResult importFromZip(File file, CoselmarUser currentUser) { + protected MassiveDocumentsImportResult importFromZip(CoselmarServicesContext servicesContext, File file, CoselmarUser currentUser) { MassiveDocumentsImportResult importResult = new MassiveDocumentsImportResult(); // File should be a Zip ZipFile zipFile; @@ -1004,10 +1076,10 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { DocumentImportModel csvModel = new DocumentImportModel(); Import<DocumentBean> importer = Import.newImport(csvModel, descriptionInputStream); - File dataDirectory = getCoselmarServicesConfig().getDataDirectory(); + File dataDirectory = servicesContext.getCoselmarServicesConfig().getDataDirectory(); String dataPath = dataDirectory.getAbsolutePath(); - String zipTempPath = dataPath + File.separator + DateUtil.formatDate(getNow(), "yyyyMMddHHmm"); - Path dir = Paths.get(zipTempPath); + String zipTempPath = dataPath + File.separator + DateUtil.formatDate(servicesContext.getNow(), "yyyyMMddHHmm"); + java.nio.file.Path dir = Paths.get(zipTempPath); try { Files.createDirectories(dir); } catch (IOException e) { @@ -1044,9 +1116,9 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { try { InputStream zipFileInputStream = zipFile.getInputStream(zipFileEntry); String fileMimeType = TikaUtils.getFileMimeType(fileName); - String futureFilePath = getDocumentFileDestPath(currentUser, fileName); + String futureFilePath = getDocumentFileDestPath(servicesContext, currentUser, fileName); - String storageFileName = getFileStorageName(fileName); + String storageFileName = getFileStorageName(servicesContext, fileName); // Push file stream in temporary folder File zipEntryFile = new File(zipTempPath + File.separator + storageFileName); @@ -1080,7 +1152,7 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { // Create document if (documentOk) { - createDocument(documentBean, fileInfos, currentUser); + createDocument(servicesContext, documentBean, fileInfos, currentUser); } } @@ -1100,23 +1172,23 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { try { // Ok, let move all files from temp storage to real one ! File tmpDir = new File(zipTempPath); - FileUtils.copyDirectory(tmpDir, new File(getUserDocumentPath(currentUser))); + FileUtils.copyDirectory(tmpDir, new File(getUserDocumentPath(servicesContext, currentUser))); FileUtils.deleteDirectory(tmpDir); - commit(); + servicesContext.getPersistenceContext().commit(); } catch (IOException e) { // Big problem if we can't move files into real folder ! String message = String.format("Unable to move files from temp folder '%s' to final folder", zipTempPath); if (log.isErrorEnabled()) { log.error(message, e); } - refreshDocumentsIndex(); + refreshDocumentsIndex(servicesContext); throw new CoselmarTechnicalException(message, e); } } else { // Something wrong happened... rollback, and refresh lucene to avoid new data - rollback(); - refreshDocumentsIndex(); + servicesContext.getPersistenceContext().rollback(); + refreshDocumentsIndex(servicesContext); } } finally { @@ -1129,14 +1201,37 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { return importResult; } - protected void refreshDocumentsIndex() { - AdminWebService adminWebService = getServicesContext().newService(AdminWebService.class); + protected void refreshDocumentsIndex(CoselmarServicesContext servicesContext) { + AdminWebService adminWebService = servicesContext.newService(AdminWebService.class); try { - adminWebService.refreshDocumentsIndex(); + adminWebService.refreshDocumentsIndex(servicesContext); } catch (IOException e) { if (log.isErrorEnabled()) { log.error("Unable to refresh Lucene Documents index. Data should be corrupted", e); } } } + + protected File getFileFromMultipart(MultipartFormDataInput uploadInput, String uploadName, String fileName) { + + File file = null; + try { + // Get file from Multipart + InputStream in = uploadInput.getFormDataPart(uploadName, InputStream.class, null); + InputPart inputPart = uploadInput.getFormDataMap().get(uploadName).get(0); + + java.nio.file.Path tempPath = Files.createTempDirectory("coselmar"); + file = new File(tempPath.toFile(), fileName); + Files.copy(in, file.toPath()); + + } catch ( + IOException e) { + if (log.isErrorEnabled()) { + log.error("error during ZipFile transfer", e); + } + + } + return file; + } + } diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/ErrorAction.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/ErrorAction.java deleted file mode 100644 index 45d1c49..0000000 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/ErrorAction.java +++ /dev/null @@ -1,83 +0,0 @@ -package fr.ifremer.coselmar.services.v1; - -/* - * #%L - * Coselmar :: Rest Services - * $Id:$ - * $HeadURL:$ - * %% - * Copyright (C) 2014 Ifremer, Code Lutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -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; - -import javax.servlet.http.HttpServletResponse; - -/** - * @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; - - } - - public Render on404(HttpContext context, Exception e) { - - CoselmarRestUtil.prepareResponse(context); - - Render render = renderError(HttpServletResponse.SC_NOT_FOUND, e.getMessage()); - return render; - - } - - public Render on403(HttpContext context, Exception e) { - - CoselmarRestUtil.prepareResponse(context); - - Render render = renderError(HttpServletResponse.SC_FORBIDDEN, e.getMessage()); - return render; - - } - - public Render on401(HttpContext context, Exception e) { - - CoselmarRestUtil.prepareResponse(context); - - Render render = renderError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage()); - return render; - - } - - public Render on409(HttpContext context, Exception e) { - - CoselmarRestUtil.prepareResponse(context); - - Render render = renderError(HttpServletResponse.SC_CONFLICT, e.getMessage()); - return render; - - } -} diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/GeneralWebService.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/GeneralWebService.java index cb9bb07..4debc07 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/GeneralWebService.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/GeneralWebService.java @@ -28,12 +28,20 @@ import com.google.common.collect.Lists; import fr.ifremer.coselmar.beans.CloudWord; import fr.ifremer.coselmar.exceptions.CoselmarTechnicalException; import fr.ifremer.coselmar.persistence.entity.CoselmarUserRole; +import fr.ifremer.coselmar.services.CoselmarServicesContext; import fr.ifremer.coselmar.services.CoselmarWebServiceSupport; import fr.ifremer.coselmar.services.indexation.TransverseIndexationService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.queryparser.classic.ParseException; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -42,15 +50,19 @@ import java.util.Map; /** * @author ymartel <martel@codelutin.com> */ +@Path("") +@Produces(MediaType.APPLICATION_JSON) public class GeneralWebService extends CoselmarWebServiceSupport { private static final Log log = LogFactory.getLog(GeneralWebService.class); protected static final List<String> RESTRICTED_ACCESS_USERS = Lists.newArrayList(CoselmarUserRole.CLIENT.name(), CoselmarUserRole.MEMBER.name()); - public List<CloudWord> getTopWords() { + @GET + @Path("/v1/general/topwords") + public List<CloudWord> getTopWords(@Context CoselmarServicesContext servicesContext) { - TransverseIndexationService questionsIndexationService = getServicesContext().newService(TransverseIndexationService.class); + TransverseIndexationService questionsIndexationService = servicesContext.newService(TransverseIndexationService.class); Map<String, Long> topTerms = null; try { diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/HealthService.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/HealthService.java index b3faad2..67422b2 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/HealthService.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/HealthService.java @@ -27,25 +27,37 @@ package fr.ifremer.coselmar.services.v1; import fr.ifremer.coselmar.beans.HealthBean; import fr.ifremer.coselmar.beans.QuestionSearchBean; import fr.ifremer.coselmar.persistence.entity.Privacy; +import fr.ifremer.coselmar.services.CoselmarServicesContext; import fr.ifremer.coselmar.services.CoselmarWebServiceSupport; import fr.ifremer.coselmar.services.indexation.QuestionsIndexationService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; + /** * @author ymartel (martel@codelutin.com) */ +@Path("") +@Produces(MediaType.APPLICATION_JSON) public class HealthService extends CoselmarWebServiceSupport { private static final Log log = LogFactory.getLog(HealthService.class); - public HealthBean getHealth() { - String version = getCoselmarServicesConfig().getVersion(); - boolean devMode = getCoselmarServicesConfig().isDevMode(); + @GET + @Path("/v1/health") + public HealthBean getHealth(@Context CoselmarServicesContext servicesContext) { + String version = servicesContext.getCoselmarServicesConfig().getVersion(); + boolean devMode = servicesContext.getCoselmarServicesConfig().isDevMode(); boolean dbUp = false; try { - getQuestionDao().count(); + servicesContext.getPersistenceContext().getQuestionDao().count(); dbUp = true; } catch (Exception e) { @@ -55,7 +67,7 @@ public class HealthService extends CoselmarWebServiceSupport { } boolean indexationUp = false; - QuestionsIndexationService questionsIndexationService = getServicesContext().newService(QuestionsIndexationService.class); + QuestionsIndexationService questionsIndexationService = servicesContext.newService(QuestionsIndexationService.class); try { QuestionSearchBean searchBean = new QuestionSearchBean(); searchBean.setPrivacy(Privacy.PUBLIC.name()); diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java index 8597f5a..60b5689 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java @@ -44,6 +44,7 @@ import fr.ifremer.coselmar.beans.UserBean; import fr.ifremer.coselmar.beans.UserWebToken; import fr.ifremer.coselmar.converter.BeanEntityConverter; import fr.ifremer.coselmar.exceptions.CoselmarTechnicalException; +import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; import fr.ifremer.coselmar.persistence.entity.CoselmarUser; import fr.ifremer.coselmar.persistence.entity.CoselmarUserGroup; import fr.ifremer.coselmar.persistence.entity.CoselmarUserRole; @@ -54,6 +55,7 @@ import fr.ifremer.coselmar.persistence.entity.Privacy; import fr.ifremer.coselmar.persistence.entity.Question; import fr.ifremer.coselmar.persistence.entity.QuestionImpl; import fr.ifremer.coselmar.persistence.entity.Status; +import fr.ifremer.coselmar.services.CoselmarServicesContext; import fr.ifremer.coselmar.services.CoselmarWebServiceSupport; import fr.ifremer.coselmar.services.errors.InvalidCredentialException; import fr.ifremer.coselmar.services.errors.NoResultException; @@ -65,7 +67,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.queryparser.classic.ParseException; -import org.debux.webmotion.server.render.Render; import org.nuiton.csv.Export; import org.nuiton.topia.persistence.TopiaIdFactory; import org.nuiton.topia.persistence.TopiaNoResultException; @@ -73,6 +74,19 @@ import org.nuiton.util.DateUtil; import org.nuiton.util.pagination.PaginationParameter; import org.nuiton.util.pagination.PaginationResult; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -86,16 +100,23 @@ import java.util.Set; /** * @author ymartel <martel@codelutin.com> */ +@Path("") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) public class QuestionsWebService extends CoselmarWebServiceSupport { private static final Log log = LogFactory.getLog(QuestionsWebService.class); protected static final List<String> RESTRICTED_ACCESS_USERS = Lists.newArrayList(CoselmarUserRole.CLIENT.name(), CoselmarUserRole.MEMBER.name()); - public void addQuestion(QuestionBean question) throws InvalidCredentialException, UnauthorizedException { + @POST + @Path("/v1/questions") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public void addQuestion(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @FormParam("question") QuestionBean question) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); UserWebToken userWebToken = checkAuthentication(authorization); // Only Supervisor can add question @@ -111,12 +132,13 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); // retrieve user who will be assigned as question supervisor - String fullId = getFullUserIdFromShort(userWebToken.getUserId()); + String fullId = getFullUserIdFromShort(persistenceContext, userWebToken.getUserId()); CoselmarUser supervisor; try { - supervisor = getCoselmarUserDao().forTopiaIdEquals(fullId).findUnique(); + supervisor = persistenceContext.getCoselmarUserDao().forTopiaIdEquals(fullId).findUnique(); } catch (TopiaNoResultException tnre) { // Should not happened, cause user are not really deleted String message = String.format("Logged user ('%s') does not exist.", fullId); @@ -133,7 +155,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Preconditions.checkNotNull(question.getThemes()); // let's go - Question questionEntity = getQuestionDao().create(); + Question questionEntity = persistenceContext.getQuestionDao().create(); questionEntity.setUnavailable(false); @@ -182,18 +204,18 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // Retrieve the clients Set<UserBean> clients = question.getClients(); if (clients != null && !clients.isEmpty()) { - Set<CoselmarUser> clientEntities = retrieveUsers(clients); + Set<CoselmarUser> clientEntities = retrieveUsers(servicesContext, clients); questionEntity.addAllClients(clientEntities); } // For participants, should create a dedicated group, // that could be used to restrict documents access Set<UserBean> participants = question.getParticipants(); - CoselmarUserGroup participantGroup = getCoselmarUserGroupDao().create(); + CoselmarUserGroup participantGroup = persistenceContext.getCoselmarUserGroupDao().create(); if (participants != null && !participants.isEmpty()) { participantGroup.setName(question.getTitle()); - Set<CoselmarUser> expertEntities = retrieveUsers(participants); + Set<CoselmarUser> expertEntities = retrieveUsers(servicesContext, participants); participantGroup.addAllMembers(expertEntities); } @@ -202,7 +224,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // Retrieve the supervisor Set<UserBean> supervisors = question.getSupervisors(); if (supervisors != null && !supervisors.isEmpty()) { - Set<CoselmarUser> supervisorEntities = retrieveUsers(supervisors); + Set<CoselmarUser> supervisorEntities = retrieveUsers(servicesContext, supervisors); questionEntity.addAllSupervisors(supervisorEntities); } @@ -213,7 +235,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // Hierarchy of questions Set<QuestionBean> parents = question.getParents(); if (parents != null && !parents.isEmpty()) { - Set<Question> questions = retrieveQuestions(parents); + Set<Question> questions = retrieveQuestions(servicesContext, parents); questionEntity.addAllParents(questions); } @@ -221,7 +243,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // Documents on init Set<DocumentBean> relatedDocuments = question.getRelatedDocuments(); if (relatedDocuments != null && !relatedDocuments.isEmpty()) { - Set<Document> documents = retrieveDocuments(relatedDocuments); + Set<Document> documents = retrieveDocuments(servicesContext, relatedDocuments); // Manage restriction list for document with Privacy.RESTRICTED for (Document document : documents) { if (document.getPrivacy() == Privacy.RESTRICTED) { @@ -239,7 +261,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Link linkEntity = null; String linkId = link.getId(); if (StringUtils.isNotBlank(linkId)) { - linkEntity = getPersistenceContext().getLinkDao().forTopiaIdEquals(getFullIdFromShort(Link.class, linkId)).findUniqueOrNull(); + linkEntity = persistenceContext.getLinkDao().forTopiaIdEquals(getFullIdFromShort(persistenceContext, Link.class, linkId)).findUniqueOrNull(); } if (linkEntity == null) { linkEntity = new LinkImpl(); @@ -248,20 +270,20 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { linkEntity.setUrl(link.getUrl()); if (StringUtils.isNotBlank(linkEntity.getTopiaId())) { - getPersistenceContext().getLinkDao().update(linkEntity); + persistenceContext.getLinkDao().update(linkEntity); } else { - getPersistenceContext().getLinkDao().create(linkEntity); + persistenceContext.getLinkDao().create(linkEntity); } questionEntity.addLinks(linkEntity); } } - commit(); + persistenceContext.commit(); - QuestionBean result = BeanEntityConverter.toBean(getPersistenceContext().getTopiaIdFactory(), questionEntity); + QuestionBean result = BeanEntityConverter.toBean(persistenceContext.getTopiaIdFactory(), questionEntity); - QuestionsIndexationService questionsIndexationService = getServicesContext().newService(QuestionsIndexationService.class); + QuestionsIndexationService questionsIndexationService = servicesContext.newService(QuestionsIndexationService.class); try { questionsIndexationService.indexQuestion(result); if (log.isDebugEnabled()) { @@ -275,48 +297,57 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } } - public List<QuestionBean> getQuestions(QuestionSearchBean searchOption) throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/questions") + public List<QuestionBean> getQuestions(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @QueryParam("searchOption") QuestionSearchBean searchOption) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); List<Question> questionList; if (searchOption != null) { - questionList = getAllFilteredQuestions(currentUser, searchOption); + questionList = getAllFilteredQuestions(servicesContext, currentUser, searchOption); } else { - questionList = getAllQuestions(currentUser); + questionList = getAllQuestions(servicesContext, currentUser); } - List<QuestionBean> result = convert(currentUser, questionList); + List<QuestionBean> result = convert(servicesContext, currentUser, questionList); return result; } - public PaginationResult<QuestionBean> getPaginatedQuestions(QuestionSearchBean searchOption) throws InvalidCredentialException, UnauthorizedException { + + @GET + @Path("/v2/questions") + public PaginationResult<QuestionBean> getPaginatedQuestions(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @QueryParam("searchOption") QuestionSearchBean searchOption) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); PaginationResult<Question> paginatedQuestions; if (searchOption != null) { - paginatedQuestions = getPaginatedFilteredQuestions(currentUser, searchOption); + paginatedQuestions = getPaginatedFilteredQuestions(servicesContext, currentUser, searchOption); } else { - List<Question> allQuestions = getAllQuestions(currentUser); + List<Question> allQuestions = getAllQuestions(servicesContext, currentUser); paginatedQuestions = PaginationResult.of(allQuestions, allQuestions.size(), PaginationParameter.of(0, -1)); } - PaginationResult<QuestionBean> result = convert(currentUser, paginatedQuestions); + PaginationResult<QuestionBean> result = convert(servicesContext, currentUser, paginatedQuestions); return result; } - public List<QuestionBean> getPublicQuestions() throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/questions/public") + public List<QuestionBean> getPublicQuestions(@Context CoselmarServicesContext servicesContext) throws InvalidCredentialException, UnauthorizedException { // No authentication needed, just filter to get last 5 public questions QuestionSearchExample searchOption = QuestionSearchExample.newDefaultSearchExample(); @@ -329,12 +360,13 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { PaginationParameter paginationParameter = PaginationParameter.of(0, 5, Question.PROPERTY_SUBMISSION_DATE, true); - PaginationResult<Question> questionList = getQuestionDao().findWithSearchExample(searchOption, paginationParameter); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + PaginationResult<Question> questionList = persistenceContext.getQuestionDao().findWithSearchExample(searchOption, paginationParameter); List<QuestionBean> result = new ArrayList<>(questionList.getElements().size()); for (Question question : questionList.getElements()) { - TopiaIdFactory topiaIdFactory = getPersistenceContext().getTopiaIdFactory(); + TopiaIdFactory topiaIdFactory = persistenceContext.getTopiaIdFactory(); QuestionBean questionBean = BeanEntityConverter.toLightBean(topiaIdFactory, question); @@ -344,10 +376,13 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return result; } - public void deleteQuestion(String questionId) throws InvalidCredentialException, UnauthorizedException { + @DELETE + @Path("/v1/questions/{questionId}") + public void deleteQuestion(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("questionId") String questionId) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); UserWebToken userWebToken = checkAuthentication(authorization); // Only Supervisor can delete question @@ -364,10 +399,11 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } - String fullUserId = getFullIdFromShort(CoselmarUser.class, userWebToken.getUserId()); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + String fullUserId = getFullIdFromShort(persistenceContext, CoselmarUser.class, userWebToken.getUserId()); try { - getCoselmarUserDao().forTopiaIdEquals(fullUserId).findUnique(); + persistenceContext.getCoselmarUserDao().forTopiaIdEquals(fullUserId).findUnique(); } catch (TopiaNoResultException tnre) { // Should not happened, cause user are not really deleted String message = String.format("Logged user ('%s') does not exist.", fullUserId); @@ -378,18 +414,18 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } // Retrieve Question - String fullQuestionId = getFullIdFromShort(Question.class, questionId); - Question question = getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); + String fullQuestionId = getFullIdFromShort(persistenceContext, Question.class, questionId); + Question question = persistenceContext.getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); // Participant group should be deleted, and so, we should remove it from Document using this group CoselmarUserGroup participantGroup = question.getParticipants(); if (participantGroup != null) { - List<Document> documents = getDocumentDao().forRestrictedListContains(participantGroup).findAll(); + List<Document> documents = persistenceContext.getDocumentDao().forRestrictedListContains(participantGroup).findAll(); for (Document document : documents) { document.removeRestrictedList(participantGroup); } question.addAllContributors(participantGroup.getMembers()); - getPersistenceContext().getCoselmarUserGroupDao().delete(participantGroup); + persistenceContext.getCoselmarUserGroupDao().delete(participantGroup); } // Question become unavailable @@ -397,10 +433,10 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { question.setStatus(Status.DELETED); - commit(); + persistenceContext.commit(); // Remove it from index too - QuestionsIndexationService questionsIndexationService = getServicesContext().newService(QuestionsIndexationService.class); + QuestionsIndexationService questionsIndexationService = servicesContext.newService(QuestionsIndexationService.class); try { questionsIndexationService.deleteQuestion(questionId); if (log.isDebugEnabled()) { @@ -414,20 +450,24 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } } - public QuestionBean getQuestion(String questionId) throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/questions/{questionId}") + public QuestionBean getQuestion(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("questionId") String questionId) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); // Supervisor can get all the question elements // Expert can get all the question elements if public or if he is participant of the question // Client can get the question (not the documents) if he is client of the question. + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); // Member cannot access to question if (CoselmarUserRole.MEMBER == currentUser.getRole()) { String message = String.format("User %s %s ('%s') is not allowed to view question", - currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(currentUser.getTopiaId())); + currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(persistenceContext, currentUser.getTopiaId())); if (log.isWarnEnabled()) { log.warn(message); } @@ -437,8 +477,8 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // Retrieve Question - String fullQuestionId = getFullIdFromShort(Question.class, questionId); - Question question = getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); + String fullQuestionId = getFullIdFromShort(persistenceContext, Question.class, questionId); + Question question = persistenceContext.getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); if (CoselmarUserRole.CLIENT == currentUser.getRole()) { // Client User can access if it is client of question @@ -446,11 +486,11 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } - QuestionBean result = BeanEntityConverter.toBean(getPersistenceContext().getTopiaIdFactory(), question); + QuestionBean result = BeanEntityConverter.toBean(persistenceContext.getTopiaIdFactory(), question); //manager child - List<Question> children = getQuestionDao().forParentsContains(question).findAll(); + List<Question> children = persistenceContext.getQuestionDao().forParentsContains(question).findAll(); for (Question child : children) { - QuestionBean childBean = BeanEntityConverter.toLightBean(getPersistenceContext().getTopiaIdFactory(), child); + QuestionBean childBean = BeanEntityConverter.toLightBean(persistenceContext.getTopiaIdFactory(), child); result.addChild(childBean); } @@ -473,10 +513,10 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { result.setPrivacy(question.getPrivacy().name()); result.setRestricted(true); for (Question parent : question.getParents()) { - result.addParent(BeanEntityConverter.toLightBean(getPersistenceContext().getTopiaIdFactory(), parent)); + result.addParent(BeanEntityConverter.toLightBean(persistenceContext.getTopiaIdFactory(), parent)); } for (Question child : children) { - QuestionBean childBean = BeanEntityConverter.toLightBean(getPersistenceContext().getTopiaIdFactory(), child); + QuestionBean childBean = BeanEntityConverter.toLightBean(persistenceContext.getTopiaIdFactory(), child); result.addChild(childBean); } } @@ -485,10 +525,14 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return result; } - public void addDocuments(String questionId, DocumentBean[] documents) throws InvalidCredentialException, UnauthorizedException { + @POST + @Path("/v1/questions/{questionId}/documents") + public void addDocuments(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("questionId") String questionId, + DocumentBean[] documents) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); UserWebToken userWebToken = checkAuthentication(authorization); // Only Supervisor can add documents @@ -507,11 +551,12 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } - String fullUserId = getFullIdFromShort(CoselmarUser.class, userWebToken.getUserId()); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + String fullUserId = getFullIdFromShort(persistenceContext, CoselmarUser.class, userWebToken.getUserId()); CoselmarUser currentUser; try { - currentUser = getCoselmarUserDao().forTopiaIdEquals(fullUserId).findUnique(); + currentUser = persistenceContext.getCoselmarUserDao().forTopiaIdEquals(fullUserId).findUnique(); } catch (TopiaNoResultException tnre) { // Should not happened, cause user are not really deleted String message = String.format("Logged user ('%s') does not exist.", fullUserId); @@ -522,8 +567,8 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } // Retrieve Question - String fullQuestionId = getFullIdFromShort(Question.class, questionId); - Question question = getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); + String fullQuestionId = getFullIdFromShort(persistenceContext, Question.class, questionId); + Question question = persistenceContext.getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); // Check expert authorization on the document checkIsParticipant(question, currentUser); @@ -533,7 +578,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Collection<Document> questionDocuments = question.getRelatedDocuments(); if (documents != null && documents.length > 0) { - Set<Document> documentEntities = retrieveDocuments(Lists.newArrayList(documents)); + Set<Document> documentEntities = retrieveDocuments(servicesContext, Lists.newArrayList(documents)); // Manage restriction list for document with Privacy.RESTRICTED for (Document document : documentEntities) { if (document.getPrivacy() == Privacy.RESTRICTED) { @@ -545,14 +590,17 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } } - commit(); + persistenceContext.commit(); } - public void saveQuestion(QuestionBean question) throws InvalidCredentialException, UnauthorizedException { + @POST + @Path("/v1/questions/{questionId}") + public void saveQuestion(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + QuestionBean question) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser supervisor = checkUserAuthentication(authorization); + CoselmarUser supervisor = checkUserAuthentication(servicesContext, authorization); // Only Supervisor can save question @@ -572,6 +620,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Preconditions.checkNotNull(question.getType()); Preconditions.checkNotNull(question.getThemes()); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); // let's go Question questionEntity; @@ -579,12 +628,12 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { String questionId = question.getId(); boolean inEdition = StringUtils.isNotBlank(questionId); if (inEdition) { - String fullQuestionId = getFullIdFromShort(Question.class, questionId); - questionEntity = getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); + String fullQuestionId = getFullIdFromShort(persistenceContext, Question.class, questionId); + questionEntity = persistenceContext.getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); } else { // or a create - questionEntity = getQuestionDao().create(); + questionEntity = persistenceContext.getQuestionDao().create(); } // Question basics @@ -657,7 +706,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Set<UserBean> clients = question.getClients(); questionEntity.clearClients(); if (clients != null && !clients.isEmpty()) { - Set<CoselmarUser> clientEntities = retrieveUsers(clients); + Set<CoselmarUser> clientEntities = retrieveUsers(servicesContext, clients); questionEntity.addAllClients(clientEntities); } @@ -665,7 +714,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Set<UserBean> contributors = question.getContributors(); questionEntity.clearContributors(); if (contributors != null && !contributors.isEmpty()) { - Set<CoselmarUser> contributorEntities = retrieveUsers(contributors); + Set<CoselmarUser> contributorEntities = retrieveUsers(servicesContext, contributors); questionEntity.addAllContributors(contributorEntities); } @@ -680,7 +729,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { participantGroup.setName(question.getTitle()); if (participants != null && !participants.isEmpty()) { - Set<CoselmarUser> expertEntities = retrieveUsers(participants); + Set<CoselmarUser> expertEntities = retrieveUsers(servicesContext, participants); // For each already assigned participants, if not in new list, assign them as contributors for (CoselmarUser participantBefore : participantGroup.getMembers()) { @@ -698,11 +747,11 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } else { // If not update, create new group - participantGroup = getCoselmarUserGroupDao().create(); + participantGroup = persistenceContext.getCoselmarUserGroupDao().create(); participantGroup.setName(question.getTitle()); if (participants != null && !participants.isEmpty()) { - Set<CoselmarUser> expertEntities = retrieveUsers(participants); + Set<CoselmarUser> expertEntities = retrieveUsers(servicesContext, participants); participantGroup.addAllMembers(expertEntities); } } @@ -712,7 +761,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Set<UserBean> supervisors = question.getSupervisors(); questionEntity.clearSupervisors(); if (supervisors != null && !supervisors.isEmpty()) { - Set<CoselmarUser> supervisorEntities = retrieveUsers(supervisors); + Set<CoselmarUser> supervisorEntities = retrieveUsers(servicesContext, supervisors); questionEntity.addAllSupervisors(supervisorEntities); } @@ -723,7 +772,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // Hierarchy of questions Set<QuestionBean> parents = question.getParents(); if (parents != null && !parents.isEmpty()) { - Set<Question> questions = retrieveQuestions(parents); + Set<Question> questions = retrieveQuestions(servicesContext, parents); questionEntity.clearParents(); questionEntity.addAllParents(questions); @@ -737,7 +786,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Set<Document> documents = null; if (relatedDocuments != null && !relatedDocuments.isEmpty()) { - documents = retrieveDocuments(relatedDocuments); + documents = retrieveDocuments(servicesContext, relatedDocuments); } // In edition : make a diff, remove restricted list for removed documents, clear documents @@ -779,7 +828,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Set<Document> closingDocuments = null; if (closingDocumentBeans != null && !closingDocumentBeans.isEmpty()) { - closingDocuments = retrieveDocuments(closingDocumentBeans); + closingDocuments = retrieveDocuments(servicesContext, closingDocumentBeans); } // In edition : make a diff, remove restricted list for removed closing documents, clear closing documents @@ -823,8 +872,8 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Link linkEntity = null; String linkId = link.getId(); if (StringUtils.isNotBlank(linkId)) { - String linkFullId = getFullIdFromShort(Link.class, linkId); - linkEntity = getPersistenceContext().getLinkDao().forTopiaIdEquals(linkFullId).findUniqueOrNull(); + String linkFullId = getFullIdFromShort(persistenceContext, Link.class, linkId); + linkEntity = persistenceContext.getLinkDao().forTopiaIdEquals(linkFullId).findUniqueOrNull(); } if (linkEntity == null) { linkEntity = new LinkImpl(); @@ -833,20 +882,20 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { linkEntity.setUrl(link.getUrl()); if (StringUtils.isNotBlank(linkEntity.getTopiaId())) { - getPersistenceContext().getLinkDao().update(linkEntity); + persistenceContext.getLinkDao().update(linkEntity); } else { - getPersistenceContext().getLinkDao().create(linkEntity); + persistenceContext.getLinkDao().create(linkEntity); } questionEntity.addLinks(linkEntity); } } - commit(); + persistenceContext.commit(); - QuestionBean result = BeanEntityConverter.toBean(getPersistenceContext().getTopiaIdFactory(), questionEntity); + QuestionBean result = BeanEntityConverter.toBean(persistenceContext.getTopiaIdFactory(), questionEntity); - QuestionsIndexationService questionsIndexationService = getServicesContext().newService(QuestionsIndexationService.class); + QuestionsIndexationService questionsIndexationService = servicesContext.newService(QuestionsIndexationService.class); try { questionsIndexationService.indexQuestion(result); if (log.isDebugEnabled()) { @@ -860,7 +909,9 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } } - public List<String> getThemes() throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/questions/themes") + public List<String> getThemes(@Context CoselmarServicesContext servicesContext) throws InvalidCredentialException, UnauthorizedException { //XXX ymartel 20141211 : do we need authentication check for that ? // // Check authentication @@ -871,12 +922,14 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // String fullCurrentUserId = getFullUserIdFromShort(userWebToken.getUserId()); // getCoselmarUserDao().forTopiaIdEquals(fullCurrentUserId).findAny(); - List<String> themes = getQuestionDao().findAllThemes(); + List<String> themes = servicesContext.getPersistenceContext().getQuestionDao().findAllThemes(); return themes; } - public List<String> getTypes() throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/questions/types") + public List<String> getTypes(@Context CoselmarServicesContext servicesContext) throws InvalidCredentialException, UnauthorizedException { //XXX ymartel 20141211 : do we need authentication check for that ? // // Check authentication @@ -887,14 +940,16 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // String fullCurrentUserId = getFullUserIdFromShort(userWebToken.getUserId()); // getCoselmarUserDao().forTopiaIdEquals(fullCurrentUserId).findAny(); - List<String> types = getQuestionDao().findAllTypes(); + List<String> types = servicesContext.getPersistenceContext().getQuestionDao().findAllTypes(); return types; } - public Render exportQuestions(QuestionSearchBean searchOption) throws InvalidCredentialException, UnauthorizedException { + public Response exportQuestions(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @QueryParam("searchOption") QuestionSearchBean searchOption) throws InvalidCredentialException, UnauthorizedException { - List<QuestionBean> questions = getQuestions(searchOption); + List<QuestionBean> questions = getQuestions(servicesContext, authorization, searchOption); QuestionExportModel exportModel = new QuestionExportModel(); @@ -908,24 +963,33 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { throw new CoselmarTechnicalException("Unable to export datas"); } - return renderDownload(IOUtils.toInputStream(exportData), "export-projects", "text/csv"); + Response.ResponseBuilder responseBuilder = Response.ok(IOUtils.toInputStream(exportData)); + responseBuilder.header("Content-Disposition", "attachment; filename=export-projects.csv"); + return responseBuilder.build(); } - public Render exportSearchedQuestions(String token, QuestionSearchBean searchOption) throws InvalidCredentialException, UnauthorizedException { + @POST + @Path("/v1/export/questions") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response exportSearchedQuestions(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @FormParam("token") String token, + @FormParam("searchOption") QuestionSearchBean searchOption) throws InvalidCredentialException, UnauthorizedException { - CoselmarUser currentUser = checkUserAuthentication(token); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, token); List<Question> questionList; if (searchOption != null) { - questionList = getAllFilteredQuestions(currentUser, searchOption); + questionList = getAllFilteredQuestions(servicesContext, currentUser, searchOption); } else { - questionList = getAllQuestions(currentUser); + questionList = getAllQuestions(servicesContext, currentUser); } - List<QuestionBean> questions = convert(currentUser, questionList); + List<QuestionBean> questions = convert(servicesContext, currentUser, questionList); QuestionExportModel exportModel = new QuestionExportModel(); @@ -939,24 +1003,30 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { throw new CoselmarTechnicalException("Unable to export datas"); } - return renderDownload(IOUtils.toInputStream(exportData), "export-projects-result.csv", "text/csv"); + Response.ResponseBuilder responseBuilder = Response.ok(IOUtils.toInputStream(exportData)); + responseBuilder.header("Content-Disposition", "attachment; filename=export-projects-result.csv"); + return responseBuilder.build(); } - public List<QuestionTreeNode> getAncestors(String questionId, int depth) throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/questions/{questionId}/ancestors") + public List<QuestionTreeNode> getAncestors(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("questionId") String questionId, int depth) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); // Supervisor can get all the question elements // Expert can get all the question elements if public or if he is participant of the question // Client can get the question (not the documents) if he is client of the question. + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); // Member cannot access to question if (CoselmarUserRole.MEMBER == currentUser.getRole()) { String message = String.format("User %s %s ('%s') is not allowed to view question", - currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(currentUser.getTopiaId())); + currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(persistenceContext, currentUser.getTopiaId())); if (log.isWarnEnabled()) { log.warn(message); } @@ -965,8 +1035,8 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } // Retrieve Question - String fullQuestionId = getFullIdFromShort(Question.class, questionId); - Question question = getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); + String fullQuestionId = getFullIdFromShort(persistenceContext, Question.class, questionId); + Question question = persistenceContext.getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); if (CoselmarUserRole.CLIENT == currentUser.getRole()) { // Client User can access if it is client of question @@ -976,7 +1046,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { List<QuestionTreeNode> result; if (depth > 0) { - result = buildAncestorsTree(fullQuestionId, depth); + result = buildAncestorsTree(servicesContext, fullQuestionId, depth); } else { result = Collections.emptyList(); } @@ -984,20 +1054,24 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return result; } - public List<QuestionTreeNode> getDescendants(String questionId, int depth) throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/questions/{questionId}/descendants") + public List<QuestionTreeNode> getDescendants(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("questionId") String questionId, int depth) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); // Supervisor can get all the question elements // Expert can get all the question elements if public or if he is participant of the question // Client can get the question (not the documents) if he is client of the question. + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); // Member cannot access to question if (CoselmarUserRole.MEMBER == currentUser.getRole()) { String message = String.format("User %s %s ('%s') is not allowed to view question", - currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(currentUser.getTopiaId())); + currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(persistenceContext, currentUser.getTopiaId())); if (log.isWarnEnabled()) { log.warn(message); } @@ -1006,8 +1080,8 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } // Retrieve Question - String fullQuestionId = getFullIdFromShort(Question.class, questionId); - Question question = getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); + String fullQuestionId = getFullIdFromShort(persistenceContext, Question.class, questionId); + Question question = persistenceContext.getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); if (CoselmarUserRole.CLIENT == currentUser.getRole()) { // Client User can access if it is client of question @@ -1017,7 +1091,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { List<QuestionTreeNode> result; if (depth > 0) { - result = buildDescendantsTree(fullQuestionId, depth); + result = buildDescendantsTree(servicesContext, fullQuestionId, depth); } else { result = Collections.emptyList(); } @@ -1025,16 +1099,21 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return result; } - public List<QuestionBean> getUserQuestions(String userId, QuestionUserRole userRole) throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/users/{userId}/projects") + public List<QuestionBean> getUserQuestions(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("userId") String userId, + @QueryParam("userRole") QuestionUserRole userRole) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getAuthorizationHeader(); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); // Member cannot access to list of questions if (CoselmarUserRole.MEMBER == currentUser.getRole()) { String message = String.format("User %s %s ('%s') is not allowed to view question", - currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(currentUser.getTopiaId())); + currentUser.getFirstname(), currentUser.getName(), getShortIdFromFull(persistenceContext, currentUser.getTopiaId())); if (log.isWarnEnabled()) { log.warn(message); } @@ -1043,7 +1122,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { QuestionSearchBean searchBean = new QuestionSearchBean(); - String userFullId = getFullUserIdFromShort(userId); + String userFullId = getFullUserIdFromShort(persistenceContext, userId); switch (userRole) { case CONTRIBUTOR: searchBean.setContributorId(userFullId); @@ -1061,28 +1140,32 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return Collections.emptyList(); } - List<Question> questionList = getAllFilteredQuestions(currentUser, searchBean); + List<Question> questionList = getAllFilteredQuestions(servicesContext, currentUser, searchBean); - List<QuestionBean> result = convert(currentUser, questionList); + List<QuestionBean> result = convert(servicesContext, currentUser, questionList); return result; } - public List<CloudWord> getTopWords(String questionId) throws InvalidCredentialException, UnauthorizedException, NoResultException { + @GET + @Path("/v1/questions/{questionId}/topwords") + public List<CloudWord> getTopWords(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("questionId") String questionId) throws InvalidCredentialException, UnauthorizedException, NoResultException { // Check authentication - String authorization = getAuthorizationHeader(); - checkUserAuthentication(authorization); + checkUserAuthentication(servicesContext, authorization); // Retrieve Question - String fullQuestionId = getFullIdFromShort(Question.class, questionId); - Question question = getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + String fullQuestionId = getFullIdFromShort(persistenceContext, Question.class, questionId); + Question question = persistenceContext.getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); List<CloudWord> topWords = new ArrayList<>(); - if (getCoselmarServicesConfig().isPostgresqlDatabase()) { + if (servicesContext.getCoselmarServicesConfig().isPostgresqlDatabase()) { try { - topWords = getQuestionDao().findTopWords(getFullIdFromShort(Question.class, questionId)); + topWords = persistenceContext.getQuestionDao().findTopWords(getFullIdFromShort(persistenceContext, Question.class, questionId)); } catch (TopiaNoResultException e) { if (log.isErrorEnabled()) { log.error("Try to find top words for non existing questionId" + questionId, e); @@ -1091,11 +1174,11 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } } else { - QuestionsIndexationService questionsIndexationService = getServicesContext().newService(QuestionsIndexationService.class); - DocumentsIndexationService documentsIndexationService = getServicesContext().newService(DocumentsIndexationService.class); + QuestionsIndexationService questionsIndexationService = servicesContext.newService(QuestionsIndexationService.class); + DocumentsIndexationService documentsIndexationService = servicesContext.newService(DocumentsIndexationService.class); try { Map<String, Long> topQuestionsTerms = questionsIndexationService.getTopQuestionsTerms(Lists.newArrayList(questionId)); - List<String> shortDocumentIds = getShortDocumentIds(question); + List<String> shortDocumentIds = getShortDocumentIds(persistenceContext, question); Map<String, Long> topDocumentsTerms = documentsIndexationService.getTopDocumentsTerms(shortDocumentIds); for (Map.Entry<String, Long> documentTermFreq : topDocumentsTerms.entrySet()) { String term = documentTermFreq.getKey(); @@ -1170,44 +1253,47 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } } - protected Set<CoselmarUser> retrieveUsers(Collection<UserBean> userBeans) { + protected Set<CoselmarUser> retrieveUsers(CoselmarServicesContext servicesContext, Collection<UserBean> userBeans) { + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); Function<UserBean, String> getIds = new Function<UserBean, String>() { @Override public String apply(UserBean userBean) { - return getFullIdFromShort(CoselmarUser.class, userBean.getId()); + return getFullIdFromShort(persistenceContext, CoselmarUser.class, userBean.getId()); } }; Collection<String> userIds = Collections2.transform(userBeans, getIds); - List<CoselmarUser> coselmarUsers = getCoselmarUserDao().forTopiaIdIn(userIds).findAll(); + List<CoselmarUser> coselmarUsers = persistenceContext.getCoselmarUserDao().forTopiaIdIn(userIds).findAll(); return new HashSet<>(coselmarUsers); } - protected Set<Question> retrieveQuestions(Collection<QuestionBean> questionBeans) { + protected Set<Question> retrieveQuestions(CoselmarServicesContext servicesContext, Collection<QuestionBean> questionBeans) { + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); Function<QuestionBean, String> getIds = new Function<QuestionBean, String>() { @Override public String apply(QuestionBean questionBean) { - return getFullIdFromShort(Question.class, questionBean.getId()); + return getFullIdFromShort(persistenceContext, Question.class, questionBean.getId()); } }; Collection<String> questionIds = Collections2.transform(questionBeans, getIds); - List<Question> questions = getQuestionDao().forTopiaIdIn(questionIds).findAll(); + List<Question> questions = persistenceContext.getQuestionDao().forTopiaIdIn(questionIds).findAll(); return new HashSet<>(questions); } - protected Set<Document> retrieveDocuments(Collection<DocumentBean> documentBeans) { + protected Set<Document> retrieveDocuments(CoselmarServicesContext servicesContext, Collection<DocumentBean> documentBeans) { + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); Function<DocumentBean, String> getIds = new Function<DocumentBean, String>() { @Override public String apply(DocumentBean documentBean) { - return getFullIdFromShort(Document.class, documentBean.getId()); + return getFullIdFromShort(persistenceContext, Document.class, documentBean.getId()); } }; Collection<String> documentIds = Collections2.transform(documentBeans, getIds); - List<Document> documents = getDocumentDao().forTopiaIdIn(documentIds).findAll(); + List<Document> documents = persistenceContext.getDocumentDao().forTopiaIdIn(documentIds).findAll(); return new HashSet<>(documents); } @@ -1226,22 +1312,23 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { * @return list of all question user is authorized to access. * @throws UnauthorizedException */ - protected List<Question> getAllQuestions(CoselmarUser currentUser) throws UnauthorizedException { + protected List<Question> getAllQuestions(CoselmarServicesContext servicesContext, CoselmarUser currentUser) throws UnauthorizedException { String currentUserRole = currentUser.getRole().name(); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); List<Question> questionList; if (StringUtils.equalsIgnoreCase(CoselmarUserRole.ADMIN.name(), currentUserRole) || StringUtils.equalsIgnoreCase(CoselmarUserRole.SUPERVISOR.name(), currentUserRole)) { - questionList = getQuestionDao().findAll(); + questionList = persistenceContext.getQuestionDao().findAll(); } else if (StringUtils.equalsIgnoreCase(CoselmarUserRole.MEMBER.name(), currentUserRole)) { - questionList = getQuestionDao().forPrivacyEquals(Privacy.PUBLIC).findAll(); + questionList = persistenceContext.getQuestionDao().forPrivacyEquals(Privacy.PUBLIC).findAll(); } else if (StringUtils.equalsIgnoreCase(CoselmarUserRole.EXPERT.name(), currentUserRole)) { - questionList = getQuestionDao().findForExpert(currentUser); + questionList = persistenceContext.getQuestionDao().findForExpert(currentUser); } else if (StringUtils.equalsIgnoreCase(CoselmarUserRole.CLIENT.name(), currentUserRole)) { - questionList = getQuestionDao().forClientsContains(currentUser).findAll(); + questionList = persistenceContext.getQuestionDao().forClientsContains(currentUser).findAll(); } else { String message = "Not allowed to access this page"; if (log.isWarnEnabled()) { @@ -1268,11 +1355,11 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { * @return list of all question user is authorized to access. * @throws UnauthorizedException * - * @deprecated use {@link #getPaginatedFilteredQuestions(CoselmarUser, QuestionSearchBean)} + * @deprecated use {@link #getPaginatedFilteredQuestions(CoselmarServicesContext, CoselmarUser, QuestionSearchBean)} */ - protected List<Question> getAllFilteredQuestions(CoselmarUser currentUser, QuestionSearchBean searchBean) throws UnauthorizedException { + protected List<Question> getAllFilteredQuestions(CoselmarServicesContext servicesContext, CoselmarUser currentUser, QuestionSearchBean searchBean) throws UnauthorizedException { - PaginationResult<Question> paginatedFilteredQuestions = getPaginatedFilteredQuestions(currentUser, searchBean); + PaginationResult<Question> paginatedFilteredQuestions = getPaginatedFilteredQuestions(servicesContext, currentUser, searchBean); return paginatedFilteredQuestions.getElements(); } @@ -1293,16 +1380,16 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { * @return {@link PaginationResult} of questions user is authorized to access. * @throws UnauthorizedException */ - protected PaginationResult<Question> getPaginatedFilteredQuestions(CoselmarUser currentUser, QuestionSearchBean searchBean) throws UnauthorizedException { + protected PaginationResult<Question> getPaginatedFilteredQuestions(CoselmarServicesContext servicesContext, CoselmarUser currentUser, QuestionSearchBean searchBean) throws UnauthorizedException { - QuestionsIndexationService questionsIndexationService = getServicesContext().newService(QuestionsIndexationService.class); + QuestionsIndexationService questionsIndexationService = servicesContext.newService(QuestionsIndexationService.class); //Try to retrieve corresponding questionIds from the index if searchBean given List<String> fromIndexQuestionIds = null; if (searchBean != null && searchBean.getFullTextSearch() != null && !searchBean.getFullTextSearch().isEmpty()) { try { List<String> questionIds = questionsIndexationService.searchQuestion(searchBean); - fromIndexQuestionIds = getQuestionsFullId(questionIds); + fromIndexQuestionIds = getQuestionsFullId(servicesContext.getPersistenceContext(), questionIds); if (log.isInfoEnabled()) { log.info("Found " + fromIndexQuestionIds.size() + " questions from index."); } @@ -1320,6 +1407,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { String currentUserRole = currentUser.getRole().name(); QuestionSearchExample searchExample = QuestionSearchExample.newDefaultSearchExample(); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); if (searchBean != null) { if (searchBean.getPage() != null) { searchExample.setPage(searchBean.getPage()); @@ -1353,26 +1441,26 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } if (StringUtils.isNotBlank(searchBean.getParticipantId())) { - CoselmarUser user = getCoselmarUserDao().forTopiaIdEquals(searchBean.getParticipantId()).findAnyOrNull(); + CoselmarUser user = persistenceContext.getCoselmarUserDao().forTopiaIdEquals(searchBean.getParticipantId()).findAnyOrNull(); if (user != null) { searchExample.setParticipant(user); } } if (StringUtils.isNotBlank(searchBean.getContributorId())) { - CoselmarUser user = getCoselmarUserDao().forTopiaIdEquals(searchBean.getContributorId()).findAnyOrNull(); + CoselmarUser user = persistenceContext.getCoselmarUserDao().forTopiaIdEquals(searchBean.getContributorId()).findAnyOrNull(); if (user != null) { example.addContributors(user); } } if (StringUtils.isNotBlank(searchBean.getSupervisorId())) { - CoselmarUser user = getCoselmarUserDao().forTopiaIdEquals(searchBean.getSupervisorId()).findAnyOrNull(); + CoselmarUser user = persistenceContext.getCoselmarUserDao().forTopiaIdEquals(searchBean.getSupervisorId()).findAnyOrNull(); if (user != null) { example.addSupervisors(user); } } if (StringUtils.isNotBlank(searchBean.getClientId())) { - CoselmarUser user = getCoselmarUserDao().forTopiaIdEquals(searchBean.getClientId()).findAnyOrNull(); + CoselmarUser user = persistenceContext.getCoselmarUserDao().forTopiaIdEquals(searchBean.getClientId()).findAnyOrNull(); if (user != null) { example.addClients(user); } @@ -1387,11 +1475,11 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { || StringUtils.equalsIgnoreCase(CoselmarUserRole.SUPERVISOR.name(), currentUserRole)) { if (fromIndexQuestionIds != null && !fromIndexQuestionIds.isEmpty()) { - paginatedQuestions = getQuestionDao().forTopiaIdIn(fromIndexQuestionIds).findPage(paginationParameter); + paginatedQuestions = persistenceContext.getQuestionDao().forTopiaIdIn(fromIndexQuestionIds).findPage(paginationParameter); // classical search with DAO } else { - paginatedQuestions = getQuestionDao().findWithSearchExample(searchExample, paginationParameter); + paginatedQuestions = persistenceContext.getQuestionDao().findWithSearchExample(searchExample, paginationParameter); } @@ -1405,30 +1493,30 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } else { if (fromIndexQuestionIds != null && !fromIndexQuestionIds.isEmpty()) { - paginatedQuestions = getQuestionDao().forTopiaIdIn(fromIndexQuestionIds).findPage(paginationParameter); + paginatedQuestions = persistenceContext.getQuestionDao().forTopiaIdIn(fromIndexQuestionIds).findPage(paginationParameter); // classical search with DAO } else { - paginatedQuestions = getQuestionDao().findWithSearchExample(searchExample, paginationParameter); + paginatedQuestions = persistenceContext.getQuestionDao().findWithSearchExample(searchExample, paginationParameter); } } // Expert : access to all public question and private question if he is participant or client } else if (StringUtils.equalsIgnoreCase(CoselmarUserRole.EXPERT.name(), currentUserRole)) { if (fromIndexQuestionIds != null && !fromIndexQuestionIds.isEmpty()) { - paginatedQuestions = getQuestionDao().findForExpert(currentUser, fromIndexQuestionIds, paginationParameter); + paginatedQuestions = persistenceContext.getQuestionDao().findForExpert(currentUser, fromIndexQuestionIds, paginationParameter); } else { - paginatedQuestions = getQuestionDao().findForExpert(currentUser, searchExample, paginationParameter); + paginatedQuestions = persistenceContext.getQuestionDao().findForExpert(currentUser, searchExample, paginationParameter); } // Client : access to question he is client } else if (StringUtils.equalsIgnoreCase(CoselmarUserRole.CLIENT.name(), currentUserRole)) { if (fromIndexQuestionIds != null && !fromIndexQuestionIds.isEmpty()) { - paginatedQuestions = getQuestionDao().findForClient(currentUser, fromIndexQuestionIds, paginationParameter); + paginatedQuestions = persistenceContext.getQuestionDao().findForClient(currentUser, fromIndexQuestionIds, paginationParameter); } else { - paginatedQuestions = getQuestionDao().findForClient(currentUser, searchExample, paginationParameter); + paginatedQuestions = persistenceContext.getQuestionDao().findForClient(currentUser, searchExample, paginationParameter); } } else { @@ -1441,12 +1529,12 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return paginatedQuestions; } - protected List<String> getQuestionsFullId(List<String> questionShortIds) { + protected List<String> getQuestionsFullId(CoselmarPersistenceContext persistenceContext, List<String> questionShortIds) { Function<String, String> getFullIds = new Function<String, String>() { @Override public String apply(String shortId) { - return Question.class.getCanonicalName() + getPersistenceContext().getTopiaIdFactory().getSeparator() + shortId; + return getFullIdFromShort(persistenceContext, Question.class, shortId); } }; @@ -1454,11 +1542,11 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return fullIds; } - protected List<QuestionBean> convert(CoselmarUser currentUser, List<Question> questionList) { + protected List<QuestionBean> convert(CoselmarServicesContext servicesContext, CoselmarUser currentUser, List<Question> questionList) { List<QuestionBean> questions = new ArrayList<>(questionList.size()); for (Question question : questionList) { - TopiaIdFactory topiaIdFactory = getPersistenceContext().getTopiaIdFactory(); + TopiaIdFactory topiaIdFactory = servicesContext.getPersistenceContext().getTopiaIdFactory(); QuestionBean questionBean; if (RESTRICTED_ACCESS_USERS.contains(currentUser.getRole().name())) { @@ -1473,11 +1561,11 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return questions; } - protected PaginationResult<QuestionBean> convert(CoselmarUser currentUser, PaginationResult<Question> paginatedQuestions) { + protected PaginationResult<QuestionBean> convert(CoselmarServicesContext servicesContext, CoselmarUser currentUser, PaginationResult<Question> paginatedQuestions) { List<QuestionBean> questions = new ArrayList<>(paginatedQuestions.getElements().size()); for (Question question : paginatedQuestions.getElements()) { - TopiaIdFactory topiaIdFactory = getPersistenceContext().getTopiaIdFactory(); + TopiaIdFactory topiaIdFactory = servicesContext.getPersistenceContext().getTopiaIdFactory(); QuestionBean questionBean; if (RESTRICTED_ACCESS_USERS.contains(currentUser.getRole().name())) { @@ -1494,13 +1582,14 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return paginatedQuestionBeans; } - protected List<QuestionTreeNode> buildAncestorsTree(String questionId, int depth) { + protected List<QuestionTreeNode> buildAncestorsTree(CoselmarServicesContext servicesContext, String questionId, int depth) { // Depth = 0 : it is the end of the tree ! if (depth == 0) { return Collections.emptyList(); } - Question question = getQuestionDao().forTopiaIdEquals(questionId).findUnique(); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + Question question = persistenceContext.getQuestionDao().forTopiaIdEquals(questionId).findUnique(); Set<Question> parents = question.getParents(); List<QuestionTreeNode> result; @@ -1515,7 +1604,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { for (Question parent : parents) { QuestionTreeNode ancestor = new QuestionTreeNode(); String parentId = parent.getTopiaId(); - ancestor.setId(getShortIdFromFull(parentId)); + ancestor.setId(getShortIdFromFull(persistenceContext, parentId)); ancestor.setTitle(parent.getTitle()); ancestor.setThemes(Sets.newHashSet(parent.getTheme())); Date deadline = parent.getDeadline(); @@ -1528,7 +1617,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } ancestor.setType(parent.getType()); // Get ancestors of this parent - List<QuestionTreeNode> parentAncestors = buildAncestorsTree(parentId, depth - 1); + List<QuestionTreeNode> parentAncestors = buildAncestorsTree(servicesContext, parentId, depth - 1); ancestor.setAncestors(parentAncestors); result.add(ancestor); } @@ -1537,14 +1626,15 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return result; } - protected List<QuestionTreeNode> buildDescendantsTree(String questionId, int depth) { + protected List<QuestionTreeNode> buildDescendantsTree(CoselmarServicesContext servicesContext, String questionId, int depth) { // Depth = 0 : it is the end of the tree ! if (depth == 0) { return Collections.emptyList(); } - Question question = getQuestionDao().forTopiaIdEquals(questionId).findUnique(); - List<Question> children = getQuestionDao().forParentsContains(question).findAll(); + CoselmarPersistenceContext persistenceContext = servicesContext.getPersistenceContext(); + Question question = persistenceContext.getQuestionDao().forTopiaIdEquals(questionId).findUnique(); + List<Question> children = persistenceContext.getQuestionDao().forParentsContains(question).findAll(); List<QuestionTreeNode> result; @@ -1558,7 +1648,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { for (Question child : children) { QuestionTreeNode descendant = new QuestionTreeNode(); String parentId = child.getTopiaId(); - descendant.setId(getShortIdFromFull(parentId)); + descendant.setId(getShortIdFromFull(persistenceContext, parentId)); descendant.setTitle(child.getTitle()); descendant.setThemes(Sets.newHashSet(child.getTheme())); Date deadline = child.getDeadline(); @@ -1571,7 +1661,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } descendant.setType(child.getType()); // Get descendants of this child - List<QuestionTreeNode> childDescendants = buildDescendantsTree(parentId, depth - 1); + List<QuestionTreeNode> childDescendants = buildDescendantsTree(servicesContext, parentId, depth - 1); descendant.setDescendants(childDescendants); result.add(descendant); } @@ -1580,14 +1670,14 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return result; } - protected List<String> getShortDocumentIds(Question question) { + protected List<String> getShortDocumentIds(CoselmarPersistenceContext persistenceContext, Question question) { List<String> shortDocumentIds = new ArrayList<>(); for (String relatedDocumentId : question.getRelatedDocumentsTopiaIds()) { - String shortIdFromFull = getShortIdFromFull(relatedDocumentId); + String shortIdFromFull = getShortIdFromFull(persistenceContext, relatedDocumentId); shortDocumentIds.add(shortIdFromFull); } for (String closingDocumentId : question.getClosingDocumentsTopiaIds()) { - String shortIdFromFull = getShortIdFromFull(closingDocumentId); + String shortIdFromFull = getShortIdFromFull(persistenceContext, closingDocumentId); shortDocumentIds.add(shortIdFromFull); } return shortDocumentIds; diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/UsersWebService.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/UsersWebService.java index 8b3fc00..1a8e2dd 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/UsersWebService.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/UsersWebService.java @@ -31,6 +31,7 @@ import com.github.mustachejava.Mustache; import com.github.mustachejava.MustacheException; import com.github.mustachejava.MustacheFactory; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; import fr.ifremer.coselmar.beans.AbstractMail; import fr.ifremer.coselmar.beans.LostPasswordMail; import fr.ifremer.coselmar.beans.UserAccountCreatedMail; @@ -45,6 +46,8 @@ import fr.ifremer.coselmar.exceptions.CoselmarTechnicalException; import fr.ifremer.coselmar.persistence.SearchRequestBean; import fr.ifremer.coselmar.persistence.entity.CoselmarUser; import fr.ifremer.coselmar.persistence.entity.CoselmarUserRole; +import fr.ifremer.coselmar.persistence.entity.CoselmarUserTopiaDao; +import fr.ifremer.coselmar.services.CoselmarServicesContext; import fr.ifremer.coselmar.services.CoselmarWebServiceSupport; import fr.ifremer.coselmar.services.errors.InvalidCredentialException; import fr.ifremer.coselmar.services.errors.MailAlreadyExistingException; @@ -56,13 +59,25 @@ import org.apache.commons.logging.Log; import org.apache.commons.mail.Email; import org.apache.commons.mail.EmailException; import org.apache.commons.mail.SimpleEmail; -import org.debux.webmotion.server.render.Render; import org.nuiton.csv.Export; import org.nuiton.topia.persistence.TopiaNoResultException; import org.nuiton.util.StringUtil; import org.nuiton.util.pagination.PaginationParameter; import org.nuiton.util.pagination.PaginationResult; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import java.io.StringWriter; import java.security.InvalidParameterException; import java.util.ArrayList; @@ -75,18 +90,24 @@ import static org.apache.commons.logging.LogFactory.getLog; /** * @author ymartel <martel@codelutin.com> */ +@Path("") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) public class UsersWebService extends CoselmarWebServiceSupport { private static final Log log = getLog(UsersWebService.class); - public UserBean getUser(String userId) throws InvalidCredentialException, UnauthorizedException, TopiaNoResultException { + @GET + @Path("/v1/users/{userId}") + public UserBean getUser(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("userId") String userId) throws InvalidCredentialException, UnauthorizedException, TopiaNoResultException { // Check authentication - String authorization = getContext().getHeader("Authorization"); - CoselmarUser curentUser = checkUserAuthentication(authorization); + CoselmarUser curentUser = checkUserAuthentication(servicesContext, authorization); // Rebuild fullId - String fullId = getFullIdFromShort(CoselmarUser.class, userId); + String fullId = getFullIdFromShort(servicesContext.getPersistenceContext(), CoselmarUser.class, userId); UserBean userBean; if (fullId.equals(curentUser.getTopiaId())) { // Current user is asking for his info : ok @@ -95,7 +116,8 @@ public class UsersWebService extends CoselmarWebServiceSupport { // Current user wanna see an other profile ; only allowed to Admin or Supervisor (if it user is a client) // Get the asked user - CoselmarUser askedUser = getCoselmarUserDao().forTopiaIdEquals(fullId).findAny(); + CoselmarUserTopiaDao coselmarUserDao = servicesContext.getPersistenceContext().getCoselmarUserDao(); + CoselmarUser askedUser = coselmarUserDao.forTopiaIdEquals(fullId).findAny(); boolean isAdmin = curentUser.getRole() == CoselmarUserRole.ADMIN; boolean isSupervisor4Client = (curentUser.getRole() == CoselmarUserRole.SUPERVISOR && askedUser.getRole() == CoselmarUserRole.CLIENT); @@ -114,18 +136,25 @@ public class UsersWebService extends CoselmarWebServiceSupport { return userBean; } - public List<UserBean> getUsers(UserSearchBean search) throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/users") + public List<UserBean> getUsers(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @QueryParam("search") UserSearchBean search) throws InvalidCredentialException, UnauthorizedException { - PaginationResult<UserBean> paginatedUsers = getPaginatedUsers(search); + PaginationResult<UserBean> paginatedUsers = getPaginatedUsers(servicesContext, authorization, search); List<UserBean> result = paginatedUsers.getElements(); return result; } - public PaginationResult<UserBean> getPaginatedUsers(UserSearchBean search) throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v2/users") + public PaginationResult<UserBean> getPaginatedUsers(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @QueryParam("search") UserSearchBean search) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getContext().getHeader("Authorization"); UserWebToken userWebToken = checkAuthentication(authorization); // Who is allowed here ? Admin and user himself @@ -148,18 +177,19 @@ public class UsersWebService extends CoselmarWebServiceSupport { CoselmarUser example = BeanEntityConverter.fromBean(search); - usersPage = getCoselmarUserDao().findAllByExample(example, search.isActiveAndInactive(), requestBean); + usersPage = servicesContext.getPersistenceContext().getCoselmarUserDao().findAllByExample(example, search.isActiveAndInactive(), requestBean); } else { PaginationParameter paginationParameter = PaginationParameter.of(0, -1); - usersPage = getCoselmarUserDao().forAll().findPage(paginationParameter); + List<CoselmarUser> all = servicesContext.getPersistenceContext().getCoselmarUserDao().forAll().findAll(); + usersPage = PaginationResult.of(all, all.size(), paginationParameter); } List<UserBean> result = new ArrayList<>(usersPage.getElements().size()); for (CoselmarUser user : usersPage.getElements()) { - String userLightId = getShortIdFromFull(user.getTopiaId()); + String userLightId = getShortIdFromFull(servicesContext.getPersistenceContext(), user.getTopiaId()); UserBean userBean = BeanEntityConverter.toBean(userLightId, user); result.add(userBean); } @@ -169,11 +199,14 @@ public class UsersWebService extends CoselmarWebServiceSupport { return paginationResult; } - public List<UserBean> getExperts(UserSearchBean search) throws InvalidCredentialException, UnauthorizedException { + @GET + @Path("/v1/users/experts") + public List<UserBean> getExperts(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @QueryParam("search") UserSearchBean search) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getContext().getHeader("Authorization"); - CoselmarUser currentUser = checkUserAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); // Who is allowed here ? Admin, Supervisor, Expert if (currentUser.getRole() != CoselmarUserRole.ADMIN @@ -197,18 +230,18 @@ public class UsersWebService extends CoselmarWebServiceSupport { CoselmarUser example = BeanEntityConverter.fromBean(search); example.setRole(CoselmarUserRole.EXPERT);// we search experts here, force it ! - PaginationResult<CoselmarUser> userPaginationResult = getCoselmarUserDao().findAllByExample(example, search.isActiveAndInactive(), requestBean); + PaginationResult<CoselmarUser> userPaginationResult = servicesContext.getPersistenceContext().getCoselmarUserDao().findAllByExample(example, search.isActiveAndInactive(), requestBean); userList = userPaginationResult.getElements(); } else { - userList = getCoselmarUserDao().forRoleEquals(CoselmarUserRole.EXPERT).findAll(); + userList = servicesContext.getPersistenceContext().getCoselmarUserDao().forRoleEquals(CoselmarUserRole.EXPERT).findAll(); } List<UserBean> result = new ArrayList<>(userList.size()); for (CoselmarUser user : userList) { - String userLightId = getShortIdFromFull(user.getTopiaId()); + String userLightId = getShortIdFromFull(servicesContext.getPersistenceContext(), user.getTopiaId()); UserBean userBean = BeanEntityConverter.toBean(userLightId, user); result.add(userBean); } @@ -216,16 +249,20 @@ public class UsersWebService extends CoselmarWebServiceSupport { return result; } - public void addUser(UserBean user) throws MailAlreadyExistingException, InvalidCredentialException, UnauthorizedException { + @POST + @Path("/v1/users") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public void addUser(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @FormParam("user") UserBean user) throws MailAlreadyExistingException, InvalidCredentialException, UnauthorizedException { Preconditions.checkNotNull(user); // Check authentication - String authorization = getAuthorizationHeader(); - UserWebToken userWebToken = checkAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); // Who is allowed here ? Admin and Superviseur - if (!StringUtils.equals(userWebToken.getRole(), CoselmarUserRole.ADMIN.name()) - && StringUtils.equals(userWebToken.getRole(), CoselmarUserRole.SUPERVISOR.name()) + if (!StringUtils.equals(currentUser.getRole().name(), CoselmarUserRole.ADMIN.name()) + && StringUtils.equals(currentUser.getRole().name(), CoselmarUserRole.SUPERVISOR.name()) && !StringUtils.equals(user.getRole(), CoselmarUserRole.CLIENT.name()) ) { if (log.isDebugEnabled()) { @@ -235,14 +272,14 @@ public class UsersWebService extends CoselmarWebServiceSupport { throw new UnauthorizedException("Not allowed to add user"); } - CoselmarUser userEntity = getCoselmarUserDao().create(); + CoselmarUser userEntity = servicesContext.getPersistenceContext().getCoselmarUserDao().create(); userEntity.setFirstname(user.getFirstName()); userEntity.setName(user.getName()); - String mail = getCleanMail(user.getMail()); + String mail = servicesContext.getCleanMail(user.getMail()); if (StringUtils.isNotBlank(mail)) { - checkMailUniqueness(mail, null); + checkMailUniqueness(servicesContext, mail, null); userEntity.setMail(mail); } @@ -253,39 +290,43 @@ public class UsersWebService extends CoselmarWebServiceSupport { String password = user.getPassword(); if (StringUtils.isBlank(password)) { - password = getServicesContext().generatePassword(); + password = servicesContext.generatePassword(); } //generate a password & a salt - String salt = getServicesContext().generateSalt(); - String encodedPassword = getServicesContext().encodePassword(salt, password); + String salt = servicesContext.generateSalt(); + String encodedPassword = servicesContext.encodePassword(salt, password); userEntity.setPassword(encodedPassword); userEntity.setSalt(salt); - commit(); + servicesContext.getPersistenceContext().commit(); // send mail to user with password if (StringUtils.isNotBlank(mail) && StringUtil.isEmail(mail)) { - UserAccountCreatedMail userAccountCreatedMail = new UserAccountCreatedMail(getServicesContext().getLocale()); + UserAccountCreatedMail userAccountCreatedMail = new UserAccountCreatedMail(servicesContext.getLocale()); userAccountCreatedMail.setUser(user); userAccountCreatedMail.setPassword(password); userAccountCreatedMail.setTo(user.getMail()); - sendMail(userAccountCreatedMail); + sendMail(servicesContext.getCoselmarServicesConfig(), userAccountCreatedMail); } } - public void modifyUser(UserBean user) throws InvalidCredentialException, UnauthorizedException, InvalidParameterException, TopiaNoResultException, MailAlreadyExistingException { + @POST + @Path("/v1/users/{userId}") + public void modifyUser(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("userId") String userId, + UserBean user) throws InvalidCredentialException, UnauthorizedException, InvalidParameterException, TopiaNoResultException, MailAlreadyExistingException { // Check authentication - String authorization = getContext().getHeader("Authorization"); UserWebToken userWebToken = checkAuthentication(authorization); boolean isAdmin = StringUtils.equals(userWebToken.getRole(), CoselmarUserRole.ADMIN.name()); boolean isSupervisor4Client = StringUtils.equals(userWebToken.getRole(), CoselmarUserRole.SUPERVISOR.name()) && StringUtils.equals(user.getRole(), CoselmarUserRole.CLIENT.name()); - String userId = user.getId(); - if (StringUtils.isBlank(userId)) { + String askedUserId = user.getId(); + if (StringUtils.isBlank(askedUserId)) { throw new InvalidParameterException("User.id is mandatory"); } @@ -295,22 +336,21 @@ public class UsersWebService extends CoselmarWebServiceSupport { } // Who is allowed here ? Admin and user himself only and Supervisor if it is a "client" type user - if (!isAdmin && !StringUtils.equals(userWebToken.getUserId(), userId) && !isSupervisor4Client) { + if (!isAdmin && !StringUtils.equals(userWebToken.getUserId(), askedUserId) && !isSupervisor4Client) { if (log.isDebugEnabled()) { - String message = String.format("A non admin user try to modify account details with shortId '%s'", userId); + String message = String.format("A non admin user try to modify account details with shortId '%s'", askedUserId); log.debug(message); } throw new UnauthorizedException("Not allowed to modify user details"); } // Ok, now, retrieve this user - String fullId = CoselmarUser.class.getCanonicalName() + - getPersistenceContext().getTopiaIdFactory().getSeparator() + userId; - CoselmarUser coselmarUser = getCoselmarUserDao().forTopiaIdEquals(fullId).findAny(); + String fullId = getFullIdFromShort(servicesContext.getPersistenceContext(), CoselmarUser.class, askedUserId); + CoselmarUser coselmarUser = servicesContext.getPersistenceContext().getCoselmarUserDao().forTopiaIdEquals(fullId).findAny(); // Last check : the password if (!isAdmin && !isSupervisor4Client) { - checkPassword(coselmarUser.getPassword(), coselmarUser.getSalt(), user.getPassword()); + checkPassword(servicesContext, coselmarUser.getPassword(), coselmarUser.getSalt(), user.getPassword()); } // Ok, now let's start the user update ! @@ -318,7 +358,7 @@ public class UsersWebService extends CoselmarWebServiceSupport { // start with mail : should be unique String mail = user.getMail(); if (StringUtils.isNotBlank(mail)) { - checkMailUniqueness(mail, fullId); + checkMailUniqueness(servicesContext, mail, fullId); coselmarUser.setMail(mail); } else { coselmarUser.setMail(null); @@ -361,60 +401,68 @@ public class UsersWebService extends CoselmarWebServiceSupport { String newPassword = user.getNewPassword(); if (StringUtils.isNotBlank(newPassword)) { - String salt = getServicesContext().generateSalt(); - String encodedPassword = getServicesContext().encodePassword(salt, newPassword); + String salt = servicesContext.generateSalt(); + String encodedPassword = servicesContext.encodePassword(salt, newPassword); coselmarUser.setSalt(salt); coselmarUser.setPassword(encodedPassword); //if it is a modification by Admin, send new mail to user if ( (isAdmin || isSupervisor4Client) && StringUtil.isEmail(coselmarUser.getMail())) { - UserPasswordChangedMail userPasswordChangedMail = new UserPasswordChangedMail(getServicesContext().getLocale()); + UserPasswordChangedMail userPasswordChangedMail = new UserPasswordChangedMail(servicesContext.getLocale()); userPasswordChangedMail.setUser(user); userPasswordChangedMail.setPassword(newPassword); userPasswordChangedMail.setTo(coselmarUser.getMail()); - sendMail(userPasswordChangedMail); + sendMail(servicesContext.getCoselmarServicesConfig(), userPasswordChangedMail); } } boolean active = user.isActive(); coselmarUser.setActive(active); - commit(); + servicesContext.getPersistenceContext().commit(); } - public Render login(String mail, String password) throws InvalidCredentialException { + @POST + @Path("/v1/users/login") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public Map<String, String> login(@Context CoselmarServicesContext servicesContext, + @FormParam("mail") String mail, + @FormParam("password") String password) throws InvalidCredentialException { Preconditions.checkNotNull(mail); Preconditions.checkNotNull(password); - CoselmarUser user = getCoselmarUserDao().forMailEquals(getCleanMail(mail)).addEquals(CoselmarUser.PROPERTY_ACTIVE, true).findAnyOrNull(); + CoselmarUser user = servicesContext.getPersistenceContext().getCoselmarUserDao().forMailEquals(servicesContext.getCleanMail(mail)).addEquals(CoselmarUser.PROPERTY_ACTIVE, true).findAnyOrNull(); if (user == null) { throw new InvalidCredentialException("Invalid mail"); } String salt = user.getSalt(); - checkPassword(user.getPassword(), salt, password); + checkPassword(servicesContext, user.getPassword(), salt, password); // return a Json Web Token for authentication - JWTSigner jwtSigner = new JWTSigner(getCoselmarServicesConfig().getWebSecurityKey()); + JWTSigner jwtSigner = new JWTSigner(servicesContext.getCoselmarServicesConfig().getWebSecurityKey()); JWTSigner.Options signerOption = new JWTSigner.Options(); signerOption.setAlgorithm(Algorithm.HS384); - String shortId = getShortIdFromFull(user.getTopiaId()); + String shortId = getShortIdFromFull(servicesContext.getPersistenceContext(), user.getTopiaId()); Map<String, Object> claims = UserWebToken.toJwtClaims(shortId, user.getFirstname(), user.getName(), user.getRole().name()); String webToken = jwtSigner.sign(claims, signerOption); - return renderJSON("jwt", webToken); + return ImmutableMap.of("jwt", webToken); } - public void deleteUser(String userId) throws InvalidCredentialException, UnauthorizedException { + @DELETE + @Path("/v1/users/{userId}") + public void deleteUser(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @PathParam("userId") String userId) throws InvalidCredentialException, UnauthorizedException { // Check authentication - String authorization = getContext().getHeader("Authorization"); - UserWebToken userWebToken = checkAuthentication(authorization); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, authorization); - boolean isAdmin = StringUtils.equals(userWebToken.getRole(), CoselmarUserRole.ADMIN.name()); + boolean isAdmin = currentUser.getRole() == CoselmarUserRole.ADMIN; // Only admin is authorized to do this if (!isAdmin) { @@ -428,43 +476,55 @@ public class UsersWebService extends CoselmarWebServiceSupport { // reconstitute full id String fullId = CoselmarUser.class.getCanonicalName() + "_" + userId; - CoselmarUser user = getCoselmarUserDao().forTopiaIdEquals(fullId).findUnique(); + CoselmarUserTopiaDao coselmarUserDao = servicesContext.getPersistenceContext().getCoselmarUserDao(); + CoselmarUser user = coselmarUserDao.forTopiaIdEquals(fullId).findUnique(); - getCoselmarUserDao().delete(user); + coselmarUserDao.delete(user); - commit(); + servicesContext.getPersistenceContext().commit(); } - public void generateNewPassword(String userMail) { + @POST + @Path("/v1/users/password") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public void generateNewPassword(@Context CoselmarServicesContext servicesContext, + @FormParam("userMail") String userMail) { // Retrieve user - CoselmarUser user = getCoselmarUserDao().forMailEquals(userMail).findUnique(); + CoselmarUser user = servicesContext.getPersistenceContext().getCoselmarUserDao().forMailEquals(userMail).findUnique(); // create new password - String password = getServicesContext().generatePassword(); + String password = servicesContext.generatePassword(); // Salt it, encode it ! - String salt = getServicesContext().generateSalt(); - String encodedPassword = getServicesContext().encodePassword(salt, password); + String salt = servicesContext.generateSalt(); + String encodedPassword = servicesContext.encodePassword(salt, password); user.setPassword(encodedPassword); user.setSalt(salt); // commit, and send mail ! - commit(); + servicesContext.getPersistenceContext().commit(); - LostPasswordMail lostPasswordMail = new LostPasswordMail(getServicesContext().getLocale()); - String shortId = getShortIdFromFull(user.getTopiaId()); + LostPasswordMail lostPasswordMail = new LostPasswordMail(servicesContext.getLocale()); + String shortId = getShortIdFromFull(servicesContext.getPersistenceContext(), user.getTopiaId()); UserBean userBean = BeanEntityConverter.toBean(shortId, user); lostPasswordMail.setUser(userBean); lostPasswordMail.setPassword(password); lostPasswordMail.setTo(user.getMail()); - sendMail(lostPasswordMail); + sendMail(servicesContext.getCoselmarServicesConfig(), lostPasswordMail); } - public Render exportSearchedUsers(String token, UserSearchBean searchOption) throws InvalidCredentialException, UnauthorizedException { + @POST + @Path("/v1/export/users") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response exportSearchedUsers(@Context CoselmarServicesContext servicesContext, + @HeaderParam(AUTHORIZATION_HEADER) String authorization, + @FormParam("token") String token, + @FormParam("searchOption") UserSearchBean searchOption) throws InvalidCredentialException, UnauthorizedException { - CoselmarUser currentUser = checkUserAuthentication(token); + CoselmarUser currentUser = checkUserAuthentication(servicesContext, token); // Who is allowed here ? Admin and user himself if (currentUser.getRole() != CoselmarUserRole.ADMIN @@ -486,18 +546,18 @@ public class UsersWebService extends CoselmarWebServiceSupport { CoselmarUser example = BeanEntityConverter.fromBean(searchOption); - PaginationResult<CoselmarUser> userPaginationResult = getCoselmarUserDao().findAllByExample(example, searchOption.isActiveAndInactive(), requestBean); + PaginationResult<CoselmarUser> userPaginationResult = servicesContext.getPersistenceContext().getCoselmarUserDao().findAllByExample(example, searchOption.isActiveAndInactive(), requestBean); userList = userPaginationResult.getElements(); } else { - userList = getCoselmarUserDao().findAll(); + userList = servicesContext.getPersistenceContext().getCoselmarUserDao().findAll(); } List<UserBean> users = new ArrayList<>(userList.size()); for (CoselmarUser user : userList) { - String userLightId = getShortIdFromFull(user.getTopiaId()); + String userLightId = getShortIdFromFull(servicesContext.getPersistenceContext(), user.getTopiaId()); UserBean userBean = BeanEntityConverter.toBean(userLightId, user); users.add(userBean); } @@ -514,7 +574,9 @@ public class UsersWebService extends CoselmarWebServiceSupport { throw new CoselmarTechnicalException("Unable to export datas", e); } - return renderDownload(IOUtils.toInputStream(exportData), "export-users-result.csv", "text/csv"); + Response.ResponseBuilder responseBuilder = Response.ok(IOUtils.toInputStream(exportData)); + responseBuilder.header("Content-Disposition", "attachment; filename=export-users-result.csv"); + return responseBuilder.build(); } @@ -528,14 +590,14 @@ public class UsersWebService extends CoselmarWebServiceSupport { * @param userId : the current user#id : this parameter is needed to exclude from the search this user, cause it could already have this mail * @throws InvalidParameterException if the mail is already used. */ - protected void checkMailUniqueness(String mail, String userId) throws MailAlreadyExistingException { + protected void checkMailUniqueness(CoselmarServicesContext servicesContext, String mail, String userId) throws MailAlreadyExistingException { boolean mailAlreadyUsed; if (StringUtils.isNotBlank(userId)) { - mailAlreadyUsed = getCoselmarUserDao().forMailEquals(mail).addNotEquals(CoselmarUser.PROPERTY_TOPIA_ID, userId).exists(); + mailAlreadyUsed = servicesContext.getPersistenceContext().getCoselmarUserDao().forMailEquals(mail).addNotEquals(CoselmarUser.PROPERTY_TOPIA_ID, userId).exists(); } else { - mailAlreadyUsed = getCoselmarUserDao().forMailEquals(mail).exists(); + mailAlreadyUsed = servicesContext.getPersistenceContext().getCoselmarUserDao().forMailEquals(mail).exists(); } if (mailAlreadyUsed) { @@ -553,8 +615,8 @@ public class UsersWebService extends CoselmarWebServiceSupport { * @param password : given password we want to check * @throws InvalidCredentialException if the given password is not the same as one from database */ - protected void checkPassword(String currentPassword, String salt, String password) throws InvalidCredentialException { - String encodedPassword = getServicesContext().encodePassword(salt, password); + protected void checkPassword(CoselmarServicesContext servicesContext, String currentPassword, String salt, String password) throws InvalidCredentialException { + String encodedPassword = servicesContext.encodePassword(salt, password); if (!encodedPassword.equals(currentPassword)){ throw new InvalidCredentialException("Invalid password given"); @@ -565,9 +627,9 @@ public class UsersWebService extends CoselmarWebServiceSupport { /////////////// MAIL PART /////////////// ///////////////////////////////////////////// - protected void sendMail(AbstractMail mail) { + protected void sendMail(CoselmarServicesConfig servicesConfig, AbstractMail mail) { - if (getCoselmarServicesConfig().isDevMode()) { + if (servicesConfig.isDevMode()) { if (log.isInfoEnabled()) { log.info("an email should have been sent if not in devMode: to = " + @@ -581,22 +643,20 @@ public class UsersWebService extends CoselmarWebServiceSupport { } else { - CoselmarServicesConfig applicationConfig = getCoselmarServicesConfig(); - - mail.setCoselmarUrl(applicationConfig.getApplicationUrl()); + mail.setCoselmarUrl(servicesConfig.getApplicationUrl()); String body = getBody(mail); if (mail.isRecipientProvided()) { Email newEmail = new SimpleEmail(); - newEmail.setHostName(applicationConfig.getSmtpHost()); - newEmail.setSmtpPort(applicationConfig.getSmtpPort()); + newEmail.setHostName(servicesConfig.getSmtpHost()); + newEmail.setSmtpPort(servicesConfig.getSmtpPort()); newEmail.setCharset(Charsets.UTF_8.name()); newEmail.setSubject(mail.getSubject()); try { - newEmail.setFrom(applicationConfig.getSmtpFrom()); + newEmail.setFrom(servicesConfig.getSmtpFrom()); String to = mail.getTo(); newEmail.addTo(to); newEmail.setMsg(body); diff --git a/coselmar-rest/src/main/resources/mapping b/coselmar-rest/src/main/resources/mapping index 154cae2..186ac6f 100644 --- a/coselmar-rest/src/main/resources/mapping +++ b/coselmar-rest/src/main/resources/mapping @@ -14,12 +14,12 @@ default.render=fr.ifremer.coselmar.services.CoselmarRender [errors] -fr.ifremer.coselmar.services.errors.InvalidCredentialException ErrorAction.on401 -fr.ifremer.coselmar.services.errors.UnauthorizedException ErrorAction.on403 -fr.ifremer.coselmar.services.errors.NoResultException ErrorAction.on404 -fr.ifremer.coselmar.services.errors.MailAlreadyExistingException ErrorAction.on409 -fr.ifremer.coselmar.exceptions.CoselmarTechnicalException ErrorAction.on500 -org.nuiton.topia.persistence.TopiaNoResultException ErrorAction.on404 +#fr.ifremer.coselmar.services.errors.InvalidCredentialException ErrorAction.on401 +#fr.ifremer.coselmar.services.errors.UnauthorizedException ErrorAction.on403 +#fr.ifremer.coselmar.services.errors.NoResultException ErrorAction.on404 +#fr.ifremer.coselmar.services.errors.MailAlreadyExistingException ErrorAction.on409 +#fr.ifremer.coselmar.exceptions.CoselmarTechnicalException ErrorAction.on500 +#org.nuiton.topia.persistence.TopiaNoResultException ErrorAction.on404 [actions] @@ -31,60 +31,60 @@ GET /v1/doc DocApi.showMapping # Documents Api -GET /v1/documents DocumentsWebService.getDocuments -GET /v2/documents DocumentsWebService.getPaginatedDocuments -GET /v2/documents/citations DocumentsWebService.getSearchBibliography -GET /v1/documents/keywords DocumentsWebService.getKeywords -GET /v1/documents/types DocumentsWebService.getTypes -GET /v1/documents/{documentId} DocumentsWebService.getDocument -GET /v1/documents/{documentId}/file DocumentsWebService.getDocumentFile -POST /v1/documents DocumentsWebService.addDocument -POST /v1/documents/{documentId} DocumentsWebService.saveDocument -POST /v1/documents/{documentId}/file DocumentsWebService.addDocumentFile -DELETE /v1/documents/{documentId} DocumentsWebService.deleteDocument +#GET /v1/documents DocumentsWebService.getDocuments +#GET /v2/documents DocumentsWebService.getPaginatedDocuments +#GET /v2/documents/citations DocumentsWebService.getSearchBibliography +#GET /v1/documents/keywords DocumentsWebService.getKeywords +#GET /v1/documents/types DocumentsWebService.getTypes +#GET /v1/documents/{documentId} DocumentsWebService.getDocument +#GET /v1/documents/{documentId}/file DocumentsWebService.getDocumentFile +#POST /v1/documents DocumentsWebService.addDocument +#POST /v1/documents/{documentId} DocumentsWebService.saveDocument +#POST /v1/documents/{documentId}/file DocumentsWebService.addDocumentFile +#DELETE /v1/documents/{documentId} DocumentsWebService.deleteDocument # Users Api -GET /v1/users UsersWebService.getUsers -GET /v2/users UsersWebService.getPaginatedUsers -GET /v1/users/experts UsersWebService.getExperts -GET /v1/users/{userId} UsersWebService.getUser -POST /v1/users/login UsersWebService.login -POST /v1/users/password UsersWebService.generateNewPassword -POST /v1/users/{userId} UsersWebService.modifyUser -POST /v1/users UsersWebService.addUser -DELETE /v1/users/{userId} UsersWebService.deleteUser -GET /v1/users/{userId}/projects QuestionsWebService.getUserQuestions +#GET /v1/users UsersWebService.getUsers +#GET /v2/users UsersWebService.getPaginatedUsers +#GET /v1/users/experts UsersWebService.getExperts +#GET /v1/users/{userId} UsersWebService.getUser +#POST /v1/users/login UsersWebService.login +#POST /v1/users/password UsersWebService.generateNewPassword +#POST /v1/users/{userId} UsersWebService.modifyUser +#POST /v1/users UsersWebService.addUser +#DELETE /v1/users/{userId} UsersWebService.deleteUser +#GET /v1/users/{userId}/projects QuestionsWebService.getUserQuestions # Questions Api -GET /v1/questions QuestionsWebService.getQuestions -GET /v2/questions QuestionsWebService.getPaginatedQuestions -GET /v1/questions/public QuestionsWebService.getPublicQuestions -GET /v1/questions/themes QuestionsWebService.getThemes -GET /v1/questions/types QuestionsWebService.getTypes -GET /v1/questions/{questionId} QuestionsWebService.getQuestion -POST /v1/questions/{questionId} QuestionsWebService.saveQuestion -POST /v1/questions/{questionId}/documents QuestionsWebService.addDocuments -POST /v1/questions QuestionsWebService.addQuestion -DELETE /v1/questions/{questionId} QuestionsWebService.deleteQuestion -GET /v1/questions/{questionId}/ancestors QuestionsWebService.getAncestors depth=2 -GET /v1/questions/{questionId}/descendants QuestionsWebService.getDescendants depth=2 -GET /v1/questions/{questionId}/topwords QuestionsWebService.getTopWords +#GET /v1/questions QuestionsWebService.getQuestions +#GET /v2/questions QuestionsWebService.getPaginatedQuestions +#GET /v1/questions/public QuestionsWebService.getPublicQuestions +#GET /v1/questions/themes QuestionsWebService.getThemes +#GET /v1/questions/types QuestionsWebService.getTypes +#GET /v1/questions/{questionId} QuestionsWebService.getQuestion +#POST /v1/questions/{questionId} QuestionsWebService.saveQuestion +#POST /v1/questions/{questionId}/documents QuestionsWebService.addDocuments +#POST /v1/questions QuestionsWebService.addQuestion +#DELETE /v1/questions/{questionId} QuestionsWebService.deleteQuestion +#GET /v1/questions/{questionId}/ancestors QuestionsWebService.getAncestors depth=2 +#GET /v1/questions/{questionId}/descendants QuestionsWebService.getDescendants depth=2 +#GET /v1/questions/{questionId}/topwords QuestionsWebService.getTopWords # Transverse Api -GET /v1/general/topwords GeneralWebService.getTopWords +#GET /v1/general/topwords GeneralWebService.getTopWords # Admin API -POST /v1/admin/lucene/index AdminWebService.refreshLuceneIndex -POST /v1/admin/documents/zip DocumentsWebService.uploadZipDocuments +#POST /v1/admin/lucene/index AdminWebService.refreshLuceneIndex +#POST /v1/admin/documents/zip DocumentsWebService.uploadZipDocuments # Export POST /v1/export/questions QuestionsWebService.exportSearchedQuestions -POST /v1/export/users UsersWebService.exportSearchedUsers +#POST /v1/export/users UsersWebService.exportSearchedUsers # Health -GET /v1/health HealthService.getHealth +#GET /v1/health HealthService.getHealth diff --git a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/AbstractCoselmarWebServiceTest.java b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/AbstractCoselmarWebServiceTest.java index 30c383c..1c4b9d5 100644 --- a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/AbstractCoselmarWebServiceTest.java +++ b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/AbstractCoselmarWebServiceTest.java @@ -25,14 +25,14 @@ package fr.ifremer.coselmar.services; */ import fr.ifremer.coselmar.persistence.CoselmarPersistenceContext; +import io.undertow.Undertow; import org.apache.commons.logging.Log; -import org.debux.webmotion.unittest.WebMotionTest; +import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.nuiton.util.DateUtil; -import java.io.File; import java.io.IOException; import java.util.Locale; @@ -41,17 +41,14 @@ import static org.apache.commons.logging.LogFactory.getLog; /** * @author ymartel <martel@codelutin.com> */ -public class AbstractCoselmarWebServiceTest extends WebMotionTest { +public class AbstractCoselmarWebServiceTest { private static final Log log = getLog(AbstractCoselmarWebServiceTest.class); @Rule public final FakeCoselmarApplicationContext application = new FakeCoselmarApplicationContext("coselmar-test.properties"); - @Override - protected int getPort() { - return application.getPort(); - } + private static UndertowJaxrsServer server; @Before public void startServer() throws Exception { @@ -78,17 +75,11 @@ public class AbstractCoselmarWebServiceTest extends WebMotionTest { applicationContext.init(); - CoselmarServicesApplicationContext.setApplicationContext(applicationContext); - - super.startServer(); - - } - - @Override - protected String getServerBaseDirectory() { + CoselmarServicesApplicationContext.setInstance(applicationContext); - return new File(application.getTestBasedir(), - "tomcat_" + application.getPort()).getAbsolutePath(); + server = new UndertowJaxrsServer().start(Undertow.builder().addHttpListener(application.getPort(), "localhost")); + server.start(); + server.deploy(CoselmarApplication.class); } @@ -101,7 +92,6 @@ public class AbstractCoselmarWebServiceTest extends WebMotionTest { application.close(); server.stop(); - server.destroy(); } diff --git a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/QuestionsWebServiceTest.java b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/QuestionsWebServiceTest.java index 87492b1..fdbb835 100644 --- a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/QuestionsWebServiceTest.java +++ b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/QuestionsWebServiceTest.java @@ -25,17 +25,34 @@ package fr.ifremer.coselmar.services; */ import com.auth0.jwt.JWTVerifier; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Sets; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import fr.ifremer.coselmar.beans.QuestionBean; import fr.ifremer.coselmar.beans.QuestionUserRole; +import fr.ifremer.coselmar.beans.UserBean; +import fr.ifremer.coselmar.converter.JacksonMapperUtil; import fr.ifremer.coselmar.converter.JsonHelper; -import org.apache.http.HttpResponse; -import org.apache.http.client.fluent.Request; -import org.apache.http.client.fluent.Response; +import fr.ifremer.coselmar.persistence.entity.Privacy; +import fr.ifremer.coselmar.providers.QuestionBeanParamConverter; +import org.jboss.resteasy.test.TestPortProvider; import org.junit.Assert; import org.junit.Test; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Form; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import java.awt.print.Book; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; @@ -63,13 +80,15 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { public void testSearchQuestions() throws Exception { //First : login ! - Request loginRequest = createRequest("/v1/users/login") - .addParameter("mail", "default.supervisor@temporary.coselmar") - .addParameter("password", "manager1234") - .Post(); + Client client = ClientBuilder.newClient(); + WebTarget loginTarget = client.target(TestPortProvider.generateURL("/v1/users/login")); - Response loginResponse = loginRequest.execute(); - String loginContent = loginResponse.returnContent().asString(); + Form loginForm = new Form() + .param("mail", "default.supervisor@temporary.coselmar") + .param("password", "manager1234"); + + Response loginResponse = loginTarget.request().post(Entity.form(loginForm)); + String loginContent = loginResponse.readEntity(String.class); Assert.assertNotNull(loginContent); showTestResult(loginContent); @@ -80,74 +99,79 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { // Create first document String documentOneTitle = "Ceci est le titre"; - Request addQuestionsRequest = createRequest("/v1/questions") - .addParameter("question", - "{title: '" + documentOneTitle + "', summary: 'ceci est le resume'," - + " submissionDate: '" + (new Date()).getTime() + "'," - + " themes: ['test', 'questionOne'], type: 'question'," - + " privacy : 'PUBLIC' }") - .Post() - .addHeader("Authorization", "Bearer " + supervisorToken); - - HttpResponse addQuestionResponse = addQuestionsRequest.execute().returnResponse(); - Assert.assertEquals(200, addQuestionResponse.getStatusLine().getStatusCode()); + + Form addQuestionForm = new Form() + .param("question", "{ \"title\": \"" + documentOneTitle + "\", \"summary\": \"ceci est le resume\"," + + " \"submissionDate\" : \"" + (new Date()).getTime() + "\"," + + " \"themes\": [\"test\", \"questionOne\"]," + + " \"type\": \"question\"," + + " \"privacy\": \"PUBLIC\" }"); + + WebTarget questionsTarget = client.target(TestPortProvider.generateURL("/v1/questions")); + + Response addQuestionResponse = questionsTarget.request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .post(Entity.form(addQuestionForm)); + + Assert.assertEquals(204, addQuestionResponse.getStatus()); // Create second document String documentTwoTitle = "There s someone missing. The question s Who?"; - addQuestionsRequest = createRequest("/v1/questions") - .addParameter("question", - "{title: '" + documentTwoTitle + "'," - + " summary: 'Something old, Something new, Something borrowed, Something blue.'," - + " submissionDate: '" + (new Date()).getTime() + "'," - + " themes: ['big bang two', 'Pandorica', 'River', 'Universe'], type: 'question'," - + " privacy : 'PUBLIC' }") - .Post() - .addHeader("Authorization", "Bearer " + supervisorToken); - - addQuestionResponse = addQuestionsRequest.execute().returnResponse(); - Assert.assertEquals(200, addQuestionResponse.getStatusLine().getStatusCode()); + addQuestionForm = new Form() + .param("question", + "{ \"title\": \"" + documentTwoTitle + "\"," + + " \"summary\": \"Something old, Something new, Something borrowed, Something blue.\"," + + " \"submissionDate\": \"" + (new Date()).getTime() + "\"," + + " \"themes\": [\"big bang two\", \"Pandorica\", \"River\", \"Universe\"]," + + " \"type\": \"question\"," + + " \"privacy\": \"PUBLIC\" }"); + + addQuestionResponse = questionsTarget.request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .post(Entity.form(addQuestionForm)); + Assert.assertEquals(204, addQuestionResponse.getStatus()); // And a third document ! String documentThreeTitle = "Private things"; - addQuestionsRequest = createRequest("/v1/questions") - .addParameter("question", - "{title: '" + documentThreeTitle + "'," - + " summary: 'This question is private, zero access for others'," - + " submissionDate: '" + (new Date()).getTime() + "'," - + " themes: ['Universe', 'test', 'zero'], type: 'question'," - + " privacy : 'PRIVATE' }") - .Post() - .addHeader("Authorization", "Bearer " + supervisorToken); - - addQuestionResponse = addQuestionsRequest.execute().returnResponse(); - Assert.assertEquals(200, addQuestionResponse.getStatusLine().getStatusCode()); + addQuestionForm = new Form() + .param("question", + "{\"title\": \"" + documentThreeTitle + "\"," + + " \"summary\": \"This question is private, zero access for others\"," + + " \"submissionDate\": \"" + (new Date()).getTime() + "\"," + + " \"themes\": [\"Universe\", \"test\", \"zero\"]," + + " \"type\": \"question\"," + + " \"privacy \": \"PRIVATE\" }"); + + addQuestionResponse = questionsTarget.request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .post(Entity.form(addQuestionForm)); + Assert.assertEquals(204, addQuestionResponse.getStatus()); // First search : as supervisor, no search bean : retrieve the three documents - Request searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{}") - .Get() - .addHeader("Authorization", "Bearer " + supervisorToken); + Response searchQuestionsResponse = questionsTarget.request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .get(); + + ObjectMapper objectMapper = JacksonMapperUtil.getMapper(); - Response searchResponse = searchRequest.execute(); - String searchResultContent = searchResponse.returnContent().asString(); - JsonHelper jsonHelper = new JsonHelper(true); - List<QuestionBean> result = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + String searchResultContent = searchQuestionsResponse.readEntity(String.class); + List<QuestionBean> result = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(3, result.size()); Assert.assertNotNull(result.get(0)); + Assert.assertEquals(documentOneTitle, result.get(0).getTitle()); Assert.assertNotNull(result.get(1)); Assert.assertNotNull(result.get(2)); // Second search : as supervisor, searchBean only with public privacy : retrieve two documents (one and two) - searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{privacy : 'PUBLIC'}") - .Get() - .addHeader("Authorization", "Bearer " + supervisorToken); + searchQuestionsResponse = questionsTarget.queryParam("searchOption", URLEncoder.encode("{\"privacy\":\"PUBLIC\"}", StandardCharsets.UTF_8.name())) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - List<QuestionBean> publicPrivacyResult = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + List<QuestionBean> publicPrivacyResult = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(2, publicPrivacyResult.size()); List<String> expectedTitles = Arrays.asList(documentOneTitle, documentTwoTitle); @@ -156,41 +180,38 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { // Third search : as supervisor, searchBean with public privacy and test keywords : retrieve documentOne - searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{privacy : 'public', fullTextSearch : ['test']}") - .Get() - .addHeader("Authorization", "Bearer " + supervisorToken); + searchQuestionsResponse = questionsTarget.queryParam("searchOption", URLEncoder.encode("{\"privacy\":\"public\",\"fullTextSearch\":[\"test\"]}", StandardCharsets.UTF_8.name())) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - List<QuestionBean> publicTestResult = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + List<QuestionBean> publicTestResult = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(1, publicTestResult.size()); Assert.assertEquals(documentOneTitle, publicTestResult.get(0).getTitle()); // Fourth search : as supervisor, searchBean with test and pandorica keywords : retrieve nothing - searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{privacy : 'public', fullTextSearch : ['test', 'pandorica']}") - .Get() - .addHeader("Authorization", "Bearer " + supervisorToken); + searchQuestionsResponse = questionsTarget.queryParam("searchOption", URLEncoder.encode("{\"privacy\":\"public\",\"fullTextSearch\":[\"test\",\"pandorica\"]}", StandardCharsets.UTF_8.name())) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - List<QuestionBean> shouldNoResult = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + List<QuestionBean> shouldNoResult = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertTrue(shouldNoResult.isEmpty()); // Fifth search : as supervisor, searchBean with test keyword : retrieve documentOne and documentThree - searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{fullTextSearch : ['test']}") - .Get() - .addHeader("Authorization", "Bearer " + supervisorToken); + searchQuestionsResponse = questionsTarget.queryParam("searchOption", URLEncoder.encode("{\"fullTextSearch\":[\"test\"]}", StandardCharsets.UTF_8.name())) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - List<QuestionBean> testKeywordResult = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + List<QuestionBean> testKeywordResult = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(2, testKeywordResult.size()); expectedTitles = Arrays.asList(documentOneTitle, documentThreeTitle); @@ -199,14 +220,13 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { // Sixth search : as supervisor, searchBean with test and universe keywords : retrieve documentThree - searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{fullTextSearch : ['test', 'Universe']}") - .Get() - .addHeader("Authorization", "Bearer " + supervisorToken); + searchQuestionsResponse = questionsTarget.queryParam("searchOption", URLEncoder.encode("{\"fullTextSearch\":[\"test\",\"Universe\"]}", StandardCharsets.UTF_8.name())) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - List<QuestionBean> testUniverseKeywordsResult = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + List<QuestionBean> testUniverseKeywordsResult = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(1, testUniverseKeywordsResult.size()); Assert.assertEquals(documentThreeTitle, testUniverseKeywordsResult.get(0).getTitle()); @@ -214,13 +234,12 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { //Have login for an expert ! - loginRequest = createRequest("/v1/users/login") - .addParameter("mail", "lambda.expert@temporary.coselmar") - .addParameter("password", "manager1234") - .Post(); + loginForm = new Form() + .param("mail", "lambda.expert@temporary.coselmar") + .param("password", "manager1234"); - loginResponse = loginRequest.execute(); - loginContent = loginResponse.returnContent().asString(); + loginResponse = loginTarget.request().post(Entity.form(loginForm)); + loginContent = loginResponse.readEntity(String.class); Assert.assertNotNull(loginContent); showTestResult(loginContent); @@ -229,14 +248,13 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { String expertToken = loginMap.get("jwt"); // Seventh search : as expert, no search bean : retrieve the two public documents - searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{}") - .Get() - .addHeader("Authorization", "Bearer " + expertToken); + searchQuestionsResponse = questionsTarget.queryParam("searchOption", URLEncoder.encode("{}", StandardCharsets.UTF_8.name())) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + expertToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - result = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + result = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(2, result.size()); expectedTitles = Arrays.asList(documentOneTitle, documentTwoTitle); @@ -244,14 +262,13 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { // Eighth search : as expert, searchBean only with public privacy : retrieve two documents (one and two) (same as seventh) - searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{privacy : 'public'}") - .Get() - .addHeader("Authorization", "Bearer " + expertToken); + searchQuestionsResponse = questionsTarget.queryParam("searchOption", URLEncoder.encode("{\"privacy\":\"public\"}", StandardCharsets.UTF_8.name())) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + expertToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - publicPrivacyResult = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + publicPrivacyResult = publicTestResult = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(2, publicPrivacyResult.size()); expectedTitles = Arrays.asList(documentOneTitle, documentTwoTitle); @@ -260,43 +277,42 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { // Ninth search : as expert, searchBean with public privacy and test keywords : retrieve documentOne - searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{privacy : 'public', fullTextSearch : ['test']}") - .Get() - .addHeader("Authorization", "Bearer " + expertToken); + searchQuestionsResponse = questionsTarget.queryParam("searchOption", URLEncoder.encode("{\"privacy\":\"public\",\"fullTextSearch\":[\"test\"]}", StandardCharsets.UTF_8.name())) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + expertToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - publicTestResult = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + publicTestResult = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(1, publicTestResult.size()); Assert.assertEquals(documentOneTitle, publicTestResult.get(0).getTitle()); // Tenth search : as supervisor, searchBean with test and pandorica keywords : retrieve nothing - searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{privacy : 'public', fullTextSearch : ['test', 'pandorica']}") - .Get() - .addHeader("Authorization", "Bearer " + expertToken); + searchQuestionsResponse = questionsTarget.queryParam("searchOption", URLEncoder.encode("{\"privacy\":\"public\",\"fullTextSearch\":[\"test\",\"pandorica\"]}", StandardCharsets.UTF_8.name())) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + expertToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - shouldNoResult = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + shouldNoResult = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertTrue(shouldNoResult.isEmpty()); // Eleventh search : as expert, searchBean with pandorica keyword : retrieve nothing (documentThree is private) - searchRequest = createRequest("/v1/questions") - .addParameter("searchOption", "{fullTextSearch : ['zero']}") - .Get() - .addHeader("Authorization", "Bearer " + expertToken); + searchQuestionsResponse = questionsTarget.queryParam("searchOption", URLEncoder.encode("{\"fullTextSearch\":[\"zero\"]}", StandardCharsets.UTF_8.name())) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + expertToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - shouldNoResult = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + shouldNoResult = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertTrue(shouldNoResult.isEmpty()); + + client.close(); } @Test @@ -305,14 +321,17 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { String webSecurityKey = getServiceContext().getCoselmarServicesConfig().getWebSecurityKey(); JWTVerifier jwtVerifier = new JWTVerifier(webSecurityKey, "audience"); + Client client = ClientBuilder.newClient(); + //First : login ! - Request loginRequest = createRequest("/v1/users/login") - .addParameter("mail", "lambda.expert@temporary.coselmar") - .addParameter("password", "manager1234") - .Post(); + WebTarget loginTarget = client.target(TestPortProvider.generateURL("/v1/users/login")); + + Form loginForm = new Form() + .param("mail", "lambda.expert@temporary.coselmar") + .param("password", "manager1234"); - Response loginResponse = loginRequest.execute(); - String loginContent = loginResponse.returnContent().asString(); + Response loginResponse = loginTarget.request().post(Entity.form(loginForm)); + String loginContent = loginResponse.readEntity(String.class); Assert.assertNotNull(loginContent); showTestResult(loginContent); @@ -324,13 +343,12 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { String expertId = (String) expertMap.get("userId"); //First : login ! - loginRequest = createRequest("/v1/users/login") - .addParameter("mail", "default.supervisor@temporary.coselmar") - .addParameter("password", "manager1234") - .Post(); + loginForm = new Form() + .param("mail", "default.supervisor@temporary.coselmar") + .param("password", "manager1234"); - loginResponse = loginRequest.execute(); - loginContent = loginResponse.returnContent().asString(); + loginResponse = loginTarget.request().post(Entity.form(loginForm)); + loginContent = loginResponse.readEntity(String.class); Assert.assertNotNull(loginContent); showTestResult(loginContent); @@ -343,63 +361,68 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { // Create first document String documentOneTitle = "Ceci est le titre"; - Request addQuestionsRequest = createRequest("/v1/questions") - .addParameter("question", - "{title: '" + documentOneTitle + "', summary: 'ceci est le resume'," - + " submissionDate: '" + (new Date()).getTime() + "'," - + " themes: ['test', 'questionOne'], type: 'question'," - + " participants: [{'id': '" + expertId + "'}]," - + " supervisors: [{'id': '" + supervisorId + "'}]," - + " privacy : 'PUBLIC' }") - .Post() - .addHeader("Authorization", "Bearer " + supervisorToken); - - HttpResponse addQuestionResponse = addQuestionsRequest.execute().returnResponse(); - Assert.assertEquals(200, addQuestionResponse.getStatusLine().getStatusCode()); + Form addQuestionForm = new Form() + .param("question", "{ \"title\": \"" + documentOneTitle + "\", \"summary\": \"ceci est le resume\"," + + " \"submissionDate\" : \"" + (new Date()).getTime() + "\"," + + " \"themes\": [\"test\", \"questionOne\"]," + + " \"type\": \"question\"," + + " \"participants\": [{\"id\":\"" + expertId + "\"}]," + + " \"supervisors\": [{\"id\": \"" + supervisorId + "\"}]," + + " \"privacy\": \"PUBLIC\" }"); + + WebTarget questionsTarget = client.target(TestPortProvider.generateURL("/v1/questions")); + + Response addQuestionResponse = questionsTarget.request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .post(Entity.form(addQuestionForm)); + + Assert.assertEquals(204, addQuestionResponse.getStatus()); // Create second document String documentTwoTitle = "There s someone missing. The question s Who?"; - addQuestionsRequest = createRequest("/v1/questions") - .addParameter("question", - "{title: '" + documentTwoTitle + "'," - + " summary: 'Something old, Something new, Something borrowed, Something blue.'," - + " submissionDate: '" + (new Date()).getTime() + "'," - + " themes: ['big bang two', 'Pandorica', 'River', 'Universe'], type: 'question'," - + " participants: [{'id': '" + expertId + "'}, {'id': '" + supervisorId + "'}]," - + " privacy : 'PUBLIC' }") - .Post() - .addHeader("Authorization", "Bearer " + supervisorToken); - - addQuestionResponse = addQuestionsRequest.execute().returnResponse(); - Assert.assertEquals(200, addQuestionResponse.getStatusLine().getStatusCode()); + addQuestionForm = new Form() + .param("question", + "{ \"title\": \"" + documentTwoTitle + "\"," + + " \"summary\": \"Something old, Something new, Something borrowed, Something blue.\"," + + " \"submissionDate\": \"" + (new Date()).getTime() + "\"," + + " \"themes\": [\"big bang two\", \"Pandorica\", \"River\", \"Universe\"]," + + " \"type\": \"question\"," + + " \"participants\": [{\"id\":\"" + expertId + "\"}, {\"id\": \"" + supervisorId + "\"}]," + + " \"privacy\": \"PUBLIC\" }"); + + addQuestionResponse = questionsTarget.request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .post(Entity.form(addQuestionForm)); + Assert.assertEquals(204, addQuestionResponse.getStatus()); // And a third document ! String documentThreeTitle = "Private things"; - addQuestionsRequest = createRequest("/v1/questions") - .addParameter("question", - "{title: '" + documentThreeTitle + "'," - + " summary: 'This question is private, zero access for others'," - + " submissionDate: '" + (new Date()).getTime() + "'," - + " themes: ['Universe', 'test', 'zero'], type: 'question'," - + " participants: [{'id': '" + supervisorId + "'}]," - + " clients: [{'id': '" + expertId + "'}]," - + " privacy : 'PRIVATE' }") - .Post() - .addHeader("Authorization", "Bearer " + supervisorToken); - - addQuestionResponse = addQuestionsRequest.execute().returnResponse(); - Assert.assertEquals(200, addQuestionResponse.getStatusLine().getStatusCode()); + addQuestionForm = new Form() + .param("question", + "{\"title\": \"" + documentThreeTitle + "\"," + + " \"summary\": \"This question is private, zero access for others\"," + + " \"submissionDate\": \"" + (new Date()).getTime() + "\"," + + " \"themes\": [\"Universe\", \"test\", \"zero\"]," + + " \"type\": \"question\"," + + " \"participants\": [{\"id\": \"" + supervisorId + "\"}]," + + " \"clients\": [{\"id\": \"" + expertId + "\"}]," + + " \"privacy \": \"PRIVATE\" }"); + + addQuestionResponse = questionsTarget.request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .post(Entity.form(addQuestionForm)); + Assert.assertEquals(204, addQuestionResponse.getStatus()); // First search : projects where expert is participant : one and two - Request searchRequest = createRequest("/v1/users/" + expertId + "/projects") - .addParameter("userRole", QuestionUserRole.PARTICIPANT.name()) - .Get() - .addHeader("Authorization", "Bearer " + supervisorToken); + WebTarget expertQuestionsTarget = client.target(TestPortProvider.generateURL("/v1/users/" + expertId + "/projects")); + Response searchQuestionsResponse = expertQuestionsTarget.queryParam("userRole", QuestionUserRole.PARTICIPANT.name()) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .get(); - Response searchResponse = searchRequest.execute(); - String searchResultContent = searchResponse.returnContent().asString(); - JsonHelper jsonHelper = new JsonHelper(true); - List<QuestionBean> result = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + String searchResultContent = searchQuestionsResponse.readEntity(String.class); + ObjectMapper objectMapper = JacksonMapperUtil.getMapper(); + List<QuestionBean> result = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(2, result.size()); Assert.assertNotNull(result.get(0)); @@ -410,14 +433,14 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { // Second search : project where supervisor is participant : two and three - searchRequest = createRequest("/v1/users/" + supervisorId + "/projects") - .addParameter("userRole", QuestionUserRole.PARTICIPANT.name()) - .Get() - .addHeader("Authorization", "Bearer " + supervisorToken); + WebTarget supervisorQuestionsTarget = client.target(TestPortProvider.generateURL("/v1/users/" + supervisorId + "/projects")); + searchQuestionsResponse = supervisorQuestionsTarget.queryParam("userRole", QuestionUserRole.PARTICIPANT.name()) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - result = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + result = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(2, result.size()); expectedTitles = Arrays.asList(documentThreeTitle, documentTwoTitle); @@ -426,28 +449,26 @@ public class QuestionsWebServiceTest extends AbstractCoselmarWebServiceTest { // Second search : project where expert is client : three - searchRequest = createRequest("/v1/users/" + expertId + "/projects") - .addParameter("userRole", QuestionUserRole.CLIENT.name()) - .Get() - .addHeader("Authorization", "Bearer " + supervisorToken); + searchQuestionsResponse = expertQuestionsTarget.queryParam("userRole", QuestionUserRole.CLIENT.name()) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .get(); - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - result = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchResultContent = searchQuestionsResponse.readEntity(String.class); + result = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(1, result.size()); Assert.assertEquals(documentThreeTitle, result.get(0).getTitle()); // Second search : project where supervisor is supervisor : all (cause he creates them) - searchRequest = createRequest("/v1/users/" + supervisorId + "/projects") - .addParameter("userRole", QuestionUserRole.SUPERVISOR.name()) - .Get() - .addHeader("Authorization", "Bearer " + supervisorToken); - - searchResponse = searchRequest.execute(); - searchResultContent = searchResponse.returnContent().asString(); - result = jsonHelper.fromJson(searchResultContent, new TypeToken<ArrayList<QuestionBean>>(){}.getType()); + searchQuestionsResponse = supervisorQuestionsTarget.queryParam("userRole", QuestionUserRole.SUPERVISOR.name()) + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + supervisorToken) + .get(); + + searchResultContent = searchQuestionsResponse.readEntity(String.class); + result = objectMapper.readValue(searchResultContent, objectMapper.getTypeFactory().constructCollectionType(List.class, QuestionBean.class)); Assert.assertEquals(3, result.size()); expectedTitles = Arrays.asList(documentOneTitle, documentTwoTitle, documentThreeTitle); diff --git a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/UsersWebServiceTest.java b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/UsersWebServiceTest.java index 39a84e4..8c6e71d 100644 --- a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/UsersWebServiceTest.java +++ b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/UsersWebServiceTest.java @@ -26,13 +26,18 @@ package fr.ifremer.coselmar.services; import com.auth0.jwt.JWTVerifier; import com.google.gson.Gson; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; -import org.apache.http.client.fluent.Request; -import org.apache.http.client.fluent.Response; +import fr.ifremer.coselmar.beans.UserBean; +import org.apache.http.HttpHeaders; +import org.jboss.resteasy.test.TestPortProvider; import org.junit.Assert; import org.junit.Test; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Form; +import javax.ws.rs.core.Response; import java.util.Locale; import java.util.Map; @@ -55,13 +60,16 @@ public class UsersWebServiceTest extends AbstractCoselmarWebServiceTest { @Test public void testAuthentication() throws Exception { - Request loginRequest = createRequest("/v1/users/login") - .addParameter("mail", "admin@temporary.coselmar") - .addParameter("password", "manager1234") - .Post(); + Client client = ClientBuilder.newClient(); + WebTarget target = client.target(TestPortProvider.generateURL("/v1/users/login")); - Response loginResponse = loginRequest.execute(); - String loginContent = loginResponse.returnContent().asString(); + Form form = new Form() + .param("mail", "admin@temporary.coselmar") + .param("password", "manager1234"); + + Response loginResponse = target.request().post(Entity.form(form)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), loginResponse.getStatus()); + String loginContent = loginResponse.readEntity(String.class); Assert.assertNotNull(loginContent); showTestResult(loginContent); @@ -72,18 +80,21 @@ public class UsersWebServiceTest extends AbstractCoselmarWebServiceTest { JWTVerifier jwtVerifier = new JWTVerifier(webSecurityKey, "audience"); String token = map.get("jwt"); jwtVerifier.verify(token); + + client.close(); } @Test public void testNewUserAuthentication() throws Exception { - Request loginRequest = createRequest("/v1/users/login") - .addParameter("mail", "admin@temporary.coselmar") - .addParameter("password", "manager1234") - .Post(); + Client client = ClientBuilder.newClient(); + WebTarget loginTarget = client.target(TestPortProvider.generateURL("/v1/users/login")); + Form loginForm = new Form() + .param("mail", "admin@temporary.coselmar") + .param("password", "manager1234"); - Response loginResponse = loginRequest.execute(); - String loginContent = loginResponse.returnContent().asString(); + Response loginResponse = loginTarget.request().post(Entity.form(loginForm)); + String loginContent = loginResponse.readEntity(String.class); Assert.assertNotNull(loginContent); showTestResult(loginContent); @@ -92,22 +103,31 @@ public class UsersWebServiceTest extends AbstractCoselmarWebServiceTest { String adminToken = loginMap.get("jwt"); + UserBean userRegistration = new UserBean(null, "test", "her", "test@test.org", null, "supervisor", "unit tester", null, true); + userRegistration.setPassword("iamatester"); + + WebTarget newUserTarget = client.target(TestPortProvider.generateURL("/v1/users")); + Form addUserForm = new Form() + .param("user", "{ \"firstName\": \"test\"," + + "\"name\": \"her\"," + + "\"mail\": \"test@test.org\"," + + "\"role\": \"supervisor\"," + + "\"qualification\": \"unit tester\"," + + "\"password\": \"iamatester\"}"); - Request addUserRequest = createRequest("/v1/users") - .addParameter("user", "{firstName: 'test', name: 'her', mail: 'test@test.org', role: 'supervisor', qualification: 'unit tester', password : 'iamatester'}") - .Post() - .addHeader("Authorization", "Bearer " + adminToken); + Response newUSerResponse = newUserTarget.request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken) + .post(Entity.form(addUserForm)); - HttpResponse addUserResponse = addUserRequest.execute().returnResponse(); - Assert.assertEquals(200, addUserResponse.getStatusLine().getStatusCode()); + Assert.assertEquals(204, newUSerResponse.getStatus()); - loginRequest = createRequest("/v1/users/login") - .addParameter("mail", "test@test.org") - .addParameter("password", "iamatester") - .Post(); + loginTarget = client.target(TestPortProvider.generateURL("/v1/users/login")); + loginForm = new Form() + .param("mail", "test@test.org") + .param("password", "iamatester"); - loginResponse = loginRequest.execute(); - loginContent = loginResponse.returnContent().asString(); + loginResponse = loginTarget.request().post(Entity.form(loginForm)); + loginContent = loginResponse.readEntity(String.class); Assert.assertNotNull(loginContent); showTestResult(loginContent); @@ -117,27 +137,31 @@ public class UsersWebServiceTest extends AbstractCoselmarWebServiceTest { JWTVerifier jwtVerifier = new JWTVerifier(webSecurityKey, "audience"); String token = newUserLoginMap.get("jwt"); jwtVerifier.verify(token); + + client.close(); } @Test public void testGenerateNewPassword() throws Exception { - Request newPasswordRequest = createRequest("/v1/users/password") - .addParameter("userMail", "lambda.expert@temporary.coselmar") - .Post(); + Client client = ClientBuilder.newClient(); + WebTarget newPasswordTarget = client.target(TestPortProvider.generateURL("/v1/users/password")); + Form newPasswordForm = new Form() + .param("userMail", "lambda.expert@temporary.coselmar"); - Response newPasswordResponse = newPasswordRequest.execute(); - Assert.assertEquals(200, newPasswordResponse.returnResponse().getStatusLine().getStatusCode()); + Response newPasswordResponse = newPasswordTarget.request().post(Entity.form(newPasswordForm)); + Assert.assertEquals(204, newPasswordResponse.getStatus()); // Try log now - Request loginRequest = createRequest("/v1/users/login") - .addParameter("mail", "lambda.expert@temporary.coselmar") - .addParameter("password", "manager1234") - .Post(); - - Response loginResponse = loginRequest.execute(); - StatusLine loginStatusLine = loginResponse.returnResponse().getStatusLine(); - Assert.assertEquals(401, loginStatusLine.getStatusCode()); + WebTarget loginTarget = client.target(TestPortProvider.generateURL("/v1/users/login")); + Form loginForm = new Form() + .param("mail", "lambda.expert@temporary.coselmar") + .param("password", "manager1234"); + + Response loginResponse = loginTarget.request().post(Entity.form(loginForm)); + Assert.assertEquals(401, loginResponse.getStatus()); + + client.close(); } } diff --git a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/v1/DocumentsWebServiceTest.java b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/v1/DocumentsWebServiceTest.java index c3f8de8..f48536e 100644 --- a/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/v1/DocumentsWebServiceTest.java +++ b/coselmar-rest/src/test/java/fr/ifremer/coselmar/services/v1/DocumentsWebServiceTest.java @@ -78,7 +78,7 @@ public class DocumentsWebServiceTest extends AbstractCoselmarServiceTest { coselmarUser.setFirstname("Jean"); getServiceContext().getPersistenceContext().commit(); - MassiveDocumentsImportResult importResult = documentsWebService.importFromZip(zipFile, coselmarUser); + MassiveDocumentsImportResult importResult = documentsWebService.importFromZip(getServiceContext(), zipFile, coselmarUser); Assert.assertNotNull(importResult); Assert.assertTrue(importResult.getMissingFiles().isEmpty()); DocumentTopiaDao documentDao = getServiceContext().getPersistenceContext().getDocumentDao(); @@ -108,7 +108,7 @@ public class DocumentsWebServiceTest extends AbstractCoselmarServiceTest { coselmarUser.setFirstname("Jean"); getServiceContext().getPersistenceContext().commit(); - MassiveDocumentsImportResult importResult = documentsWebService.importFromZip(zipFile, coselmarUser); + MassiveDocumentsImportResult importResult = documentsWebService.importFromZip(getServiceContext(), zipFile, coselmarUser); Assert.assertNotNull(importResult); Assert.assertFalse(importResult.getMissingFiles().isEmpty()); Assert.assertEquals(1, importResult.getMissingFiles().size()); diff --git a/coselmar-ui/src/main/webapp/js/coselmar-controllers.js b/coselmar-ui/src/main/webapp/js/coselmar-controllers.js index 3f6536c..3eb64ff 100644 --- a/coselmar-ui/src/main/webapp/js/coselmar-controllers.js +++ b/coselmar-ui/src/main/webapp/js/coselmar-controllers.js @@ -2188,6 +2188,7 @@ coselmarControllers.controller("AdminCtrl", ['$scope', '$routeParams', '$locatio } else { $scope.status.massimport = "fail"; $scope.status.importResult = importResult; + console.log(importResult); } },function(error) { diff --git a/pom.xml b/pom.xml index 346b73b..b8488aa 100644 --- a/pom.xml +++ b/pom.xml @@ -88,7 +88,7 @@ <platform>codelutin.com</platform> <!-- Java version --> - <javaVersion>1.7</javaVersion> + <javaVersion>1.8</javaVersion> <!--TODO remove this when idea won't ask to change jdk level at each pom modification--> <maven.compiler.source>${javaVersion}</maven.compiler.source> <!--TODO remove this when idea won't ask to change jdk level at each pom modification--> @@ -115,9 +115,7 @@ <!-- Site configuration --> <locales>fr</locales> - <!-- customized versions --> - <!--<webmotionVersion>2.4.1-20140826-pollen2</webmotionVersion>--> - <webmotionVersion>2.5.3</webmotionVersion> + <resteasy.version>3.6.3.Final</resteasy.version> <nuitonI18nVersion>3.3</nuitonI18nVersion> <eugenePluginVersion>2.13</eugenePluginVersion> @@ -393,17 +391,75 @@ </dependency> <!-- web exposition --> + + <!-- REASTEasy, for webservices --> <dependency> - <groupId>org.debux.webmotion</groupId> - <artifactId>webmotion</artifactId> - <version>${webmotionVersion}</version> - <exclusions> - <exclusion> - <groupId>javassist</groupId> - <artifactId>javassist</artifactId> - </exclusion> - </exclusions> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-jaxrs</artifactId> + <version>${resteasy.version}</version> + </dependency> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-jaxb-provider</artifactId> + <version>${resteasy.version}</version> + <scope>runtime</scope> + </dependency> + <!-- Multipart support --> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-multipart-provider</artifactId> + <version>${resteasy.version}</version> </dependency> + <!-- to run test on API --> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-undertow</artifactId> + <version>${resteasy.version}</version> + <scope>test</scope> + </dependency> + + <!-- transitive dependency from resteasy --> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + <version>4.4</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + <version>2.1</version> + </dependency> + <!--<dependency>--> + <!--<groupId>org.jboss.spec.javax.ws.rs</groupId>--> + <!--<artifactId>jboss-jaxrs-api_2.1_spec</artifactId>--> + <!--<version>1.0.0.Final</version>--> + <!--</dependency>--> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>2.8.9</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + <version>2.8.9</version> + </dependency> + + <!-- needed for Servlet 3 --> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-servlet-initializer</artifactId> + <version>${resteasy.version}</version> + <scope>runtime</scope> + </dependency> + <!-- needed for JSON response --> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-jackson2-provider</artifactId> + <version>${resteasy.version}</version> + </dependency> + <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> @@ -556,12 +612,6 @@ <version>${topiaVersion}</version> <scope>test</scope> </dependency> - <dependency> - <groupId>org.debux.webmotion</groupId> - <artifactId>webmotion-unittest</artifactId> - <version>${webmotionVersion}</version> - <scope>test</scope> - </dependency> <!-- for embedded test --> <dependency> -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.