diff --git a/docs-core/pom.xml b/docs-core/pom.xml
index cd58f6b9..69acf4c0 100644
--- a/docs-core/pom.xml
+++ b/docs-core/pom.xml
@@ -26,6 +26,11 @@
hibernate-entitymanager
+
+ org.hibernate
+ hibernate-validator
+
+
joda-time
diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/file/theme/ThemeDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/file/theme/ThemeDao.java
deleted file mode 100644
index c82989d6..00000000
--- a/docs-core/src/main/java/com/sismics/docs/core/dao/file/theme/ThemeDao.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.sismics.docs.core.dao.file.theme;
-
-import com.google.common.collect.Lists;
-import com.sismics.docs.core.util.DirectoryUtil;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Theme DAO.
- *
- * @author jtremeaux
- */
-public class ThemeDao {
- private final static FilenameFilter CSS_FILTER = new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.endsWith(".css") || name.endsWith(".less");
- }
- };
-
- /**
- * Return the list of all themes.
- *
- * @return List of themes
- */
- public List findAll() {
- final File themeDirectory = DirectoryUtil.getThemeDirectory();
- if (themeDirectory != null) {
- return Lists.newArrayList(themeDirectory.list(CSS_FILTER));
- } else {
- return new ArrayList();
- }
- }
-
-}
diff --git a/docs-core/src/main/java/com/sismics/docs/core/util/DirectoryUtil.java b/docs-core/src/main/java/com/sismics/docs/core/util/DirectoryUtil.java
index 38b410da..dfbab290 100644
--- a/docs-core/src/main/java/com/sismics/docs/core/util/DirectoryUtil.java
+++ b/docs-core/src/main/java/com/sismics/docs/core/util/DirectoryUtil.java
@@ -1,9 +1,10 @@
package com.sismics.docs.core.util;
-import com.sismics.util.EnvironmentUtil;
+import java.io.File;
+
import org.apache.commons.lang.StringUtils;
-import java.io.File;
+import com.sismics.util.EnvironmentUtil;
/**
* Utilities to gain access to the storage directories used by the application.
@@ -18,27 +19,27 @@ public class DirectoryUtil {
*/
public static File getBaseDataDirectory() {
File baseDataDir = null;
- if (EnvironmentUtil.getWebappRoot() != null) {
- // We are in a webapp environment
- if (StringUtils.isNotBlank(EnvironmentUtil.getDocsHome())) {
- // If the docs.home property is set then use it
- baseDataDir = new File(EnvironmentUtil.getDocsHome());
- if (!baseDataDir.isDirectory()) {
- baseDataDir.mkdirs();
- }
- } else {
- // Use the base of the Webapp directory
- baseDataDir = new File(EnvironmentUtil.getWebappRoot() + File.separator + "sismicsdocs");
- if (!baseDataDir.isDirectory()) {
- baseDataDir.mkdirs();
- }
+ if (StringUtils.isNotBlank(EnvironmentUtil.getDocsHome())) {
+ // If the docs.home property is set then use it
+ baseDataDir = new File(EnvironmentUtil.getDocsHome());
+ } else if (EnvironmentUtil.isUnitTest()) {
+ // For unit testing, use a temporary directory
+ baseDataDir = new File(System.getProperty("java.io.tmpdir"));
+ } else {
+ // We are in a webapp environment and nothing is specified, use the default directory for this OS
+ if (EnvironmentUtil.isUnix()) {
+ baseDataDir = new File("/var/docs");
+ } if (EnvironmentUtil.isWindows()) {
+ baseDataDir = new File(EnvironmentUtil.getWindowsAppData() + "\\Sismics\\Docs");
+ } else if (EnvironmentUtil.isMacOs()) {
+ baseDataDir = new File(EnvironmentUtil.getMacOsUserHome() + "/Library/Sismics/Docs");
}
}
- if (baseDataDir == null) {
- // Or else (for unit testing), use a temporary directory
- baseDataDir = new File(System.getProperty("java.io.tmpdir"));
+
+ if (baseDataDir != null && !baseDataDir.isDirectory()) {
+ baseDataDir.mkdirs();
}
-
+
return baseDataDir;
}
@@ -78,25 +79,6 @@ public class DirectoryUtil {
return getDataSubDirectory("log");
}
- /**
- * Returns the themes directory.
- *
- * @return Theme directory.
- */
- public static File getThemeDirectory() {
- String webappRoot = EnvironmentUtil.getWebappRoot();
- File themeDir = null;
- if (webappRoot != null) {
- themeDir = new File(webappRoot + File.separator + "style" + File.separator + "theme");
- } else {
- themeDir = new File(DirectoryUtil.class.getResource("/style/theme").getFile());
- }
- if (themeDir != null && themeDir.isDirectory()) {
- return themeDir;
- }
- return null;
- }
-
/**
* Returns a subdirectory of the base data directory
*
diff --git a/docs-core/src/main/java/com/sismics/util/EnvironmentUtil.java b/docs-core/src/main/java/com/sismics/util/EnvironmentUtil.java
index 8fbff574..791956da 100644
--- a/docs-core/src/main/java/com/sismics/util/EnvironmentUtil.java
+++ b/docs-core/src/main/java/com/sismics/util/EnvironmentUtil.java
@@ -9,7 +9,7 @@ public class EnvironmentUtil {
private static String OS = System.getProperty("os.name").toLowerCase();
- private static String TEST_ENV = System.getProperty("test");
+ private static String APPLICATION_MODE = System.getProperty("application.mode");
private static String WINDOWS_APPDATA = System.getenv("APPDATA");
@@ -18,9 +18,9 @@ public class EnvironmentUtil {
private static String DOCS_HOME = System.getProperty("docs.home");
/**
- * Web application root.
+ * In a web application context.
*/
- private static String webappRoot;
+ private static boolean webappContext;
/**
* Returns true if running under Microsoft Windows.
@@ -55,10 +55,18 @@ public class EnvironmentUtil {
* @return Unit testing environment
*/
public static boolean isUnitTest() {
- return webappRoot == null ||
- TEST_ENV != null && "true".equals(TEST_ENV);
+ return !webappContext || isDevMode();
}
+ /**
+ * Return true if we are in dev mode.
+ *
+ * @return Dev mode
+ */
+ public static boolean isDevMode() {
+ return "dev".equalsIgnoreCase(APPLICATION_MODE);
+ }
+
/**
* Returns the MS Windows AppData directory of this user.
*
@@ -87,20 +95,20 @@ public class EnvironmentUtil {
}
/**
- * Getter of webappRoot.
+ * Getter of webappContext.
*
- * @return webappRoot
+ * @return webappContext
*/
- public static String getWebappRoot() {
- return webappRoot;
+ public static boolean isWebappContext() {
+ return webappContext;
}
/**
- * Setter of webappRoot.
+ * Setter of webappContext.
*
- * @param webappRoot webappRoot
+ * @param webappContext webappContext
*/
- public static void setWebappRoot(String webappRoot) {
- EnvironmentUtil.webappRoot = webappRoot;
+ public static void setWebappContext(boolean webappContext) {
+ EnvironmentUtil.webappContext = webappContext;
}
}
diff --git a/docs-parent/pom.xml b/docs-parent/pom.xml
index 3b06b0b7..44d9d50a 100644
--- a/docs-parent/pom.xml
+++ b/docs-parent/pom.xml
@@ -26,7 +26,7 @@
1.6.6
4.7
1.4.188
- 1.17
+ 2.21
0.3m
4.2.0
4.2
@@ -34,12 +34,11 @@
1.49
2.8.2
4.1.0.Final
- 1.9.64
+ 3.1.0
9.2.13.v20150730
9.2.13.v20150730
9.2.13.v20150730
- 3.0.20100224
1.8
@@ -163,9 +162,9 @@
- org.mortbay.jetty
- servlet-api
- ${org.mortbay.jetty.servlet-api.version}
+ javax.servlet
+ javax.servlet-api
+ ${javax.servlet.javax.servlet-api.version}
@@ -229,47 +228,54 @@
- com.sun.jersey
- jersey-server
- ${com.sun.jersey.version}
-
-
-
- com.sun.jersey
- jersey-bundle
- ${com.sun.jersey.version}
-
-
-
- com.sun.jersey
- jersey-json
- ${com.sun.jersey.version}
-
-
-
- com.sun.jersey.contribs
- jersey-multipart
- ${com.sun.jersey.version}
-
-
-
- com.sun.jersey
- jersey-client
- ${com.sun.jersey.version}
+ org.glassfish.jersey.containers
+ jersey-container-servlet
+ ${org.glassfish.jersey.version}
- com.sun.grizzly
- grizzly-servlet-webserver
- ${com.sun.grizzly.version}
+ org.glassfish.jersey.media
+ jersey-media-json-processing
+ ${org.glassfish.jersey.version}
- com.sun.jersey.jersey-test-framework
- jersey-test-framework-grizzly2
- ${com.sun.jersey.version}
+ org.glassfish.jersey.media
+ jersey-media-multipart
+ ${org.glassfish.jersey.version}
+
+
+
+ org.glassfish.jersey.core
+ jersey-client
+ ${org.glassfish.jersey.version}
+
+
+
+ org.glassfish.jersey.test-framework.providers
+ jersey-test-framework-provider-bundle
+ pom
+ ${org.glassfish.jersey.version}
+
+
+
+ org.glassfish.jersey.test-framework.providers
+ jersey-test-framework-provider-external
+ ${org.glassfish.jersey.version}
+
+ org.glassfish.jersey.test-framework.providers
+ jersey-test-framework-provider-grizzly2
+ ${org.glassfish.jersey.version}
+
+
+
+ org.glassfish.jersey.containers
+ jersey-container-grizzly2-servlet
+ ${org.glassfish.jersey.version}
+
+
com.h2database
h2
@@ -288,6 +294,12 @@
${org.hibernate.hibernate.version}
+
+ org.hibernate
+ hibernate-validator
+ ${org.hibernate.hibernate.version}
+
+
commons-dbcp
commons-dbcp
diff --git a/docs-stress/pom.xml b/docs-stress/pom.xml
index 6b7c1efe..6d369769 100644
--- a/docs-stress/pom.xml
+++ b/docs-stress/pom.xml
@@ -17,10 +17,15 @@
- com.sun.jersey
+ org.glassfish.jersey.core
jersey-client
-
+
+
+ org.glassfish.jersey.media
+ jersey-media-multipart
+
+
com.sismics.docs
diff --git a/docs-stress/src/main/java/com/sismics/docs/stress/Main.java b/docs-stress/src/main/java/com/sismics/docs/stress/Main.java
index fa349ed2..788af740 100644
--- a/docs-stress/src/main/java/com/sismics/docs/stress/Main.java
+++ b/docs-stress/src/main/java/com/sismics/docs/stress/Main.java
@@ -1,6 +1,5 @@
package com.sismics.docs.stress;
-import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
@@ -8,25 +7,30 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
+import javax.json.JsonObject;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response.Status;
import junit.framework.Assert;
-import org.codehaus.jettison.json.JSONObject;
+import org.glassfish.jersey.client.ClientResponse;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import com.sismics.docs.rest.filter.CookieAuthenticationFilter;
+import com.google.common.io.Resources;
import com.sismics.docs.rest.util.ClientUtil;
-import com.sun.jersey.api.client.Client;
-import com.sun.jersey.api.client.ClientResponse;
-import com.sun.jersey.api.client.ClientResponse.Status;
-import com.sun.jersey.api.client.WebResource;
-import com.sun.jersey.core.util.MultivaluedMapImpl;
-import com.sun.jersey.multipart.FormDataBodyPart;
-import com.sun.jersey.multipart.FormDataMultiPart;
+import com.sismics.util.filter.TokenBasedSecurityFilter;
/**
* Stress app for Sismics Docs.
@@ -45,7 +49,7 @@ public class Main {
private static final int TAG_PER_USER_COUNT = 20;
private static final int FILE_PER_DOCUMENT_COUNT = 0;
- private static Client client = Client.create();
+ private static Client client = ClientBuilder.newClient();
private static ClientUtil clientUtil;
private static Set userSet = Sets.newHashSet();
@@ -54,11 +58,12 @@ public class Main {
* Entry point.
*
* @param args Args
+ * @throws Exception
*/
- public static void main(String[] args) {
+ public static void main(String[] args) throws Exception {
log.info("Starting stress test...");
- WebResource resource = client.resource(API_URL);
+ WebTarget resource = client.target(API_URL);
clientUtil = new ClientUtil(resource);
// Create users
@@ -72,17 +77,16 @@ public class Main {
// Create tags for each user
int tagCreatedCount = 1;
for (User user : userSet) {
- WebResource tagResource = resource.path("/tag");
- tagResource.addFilter(new CookieAuthenticationFilter(user.authToken));
+ Invocation.Builder tagResource = resource.path("/tag").request()
+ .cookie(TokenBasedSecurityFilter.COOKIE_NAME, user.authToken);
for (int j = 0; j < TAG_PER_USER_COUNT; j++) {
- MultivaluedMapImpl postParams = new MultivaluedMapImpl();
+ Form form = new Form();
String name = generateString();
- postParams.add("name", name);
- postParams.add("color", "#ff0000");
- ClientResponse response = tagResource.put(ClientResponse.class, postParams);
- JSONObject json = response.getEntity(JSONObject.class);
- user.tagList.add(json.optString("id"));
+ form.param("name", name);
+ form.param("color", "#ff0000");
+ JsonObject json = tagResource.put(Entity.form(form), JsonObject.class);
+ user.tagList.add(json.getString("id"));
log.info("Created tag " + (tagCreatedCount++) + "/" + TAG_PER_USER_COUNT * USER_COUNT);
}
}
@@ -91,33 +95,32 @@ public class Main {
int documentCreatedCount = 1;
for (User user : userSet) {
for (int i = 0; i < DOCUMENT_PER_USER_COUNT; i++) {
- WebResource documentResource = resource.path("/document");
- documentResource.addFilter(new CookieAuthenticationFilter(user.authToken));
- MultivaluedMapImpl postParams = new MultivaluedMapImpl();
- postParams.add("title", generateString());
- postParams.add("description", generateString());
- postParams.add("tags", user.tagList.get(ThreadLocalRandom.current().nextInt(user.tagList.size()))); // Random tag
- postParams.add("language", "eng");
long createDate = new Date().getTime();
- postParams.add("create_date", createDate);
- ClientResponse response = documentResource.put(ClientResponse.class, postParams);
- JSONObject json = response.getEntity(JSONObject.class);
- String documentId = json.optString("id");
+ Form form = new Form()
+ .param("title", generateString())
+ .param("description", generateString())
+ .param("tags", user.tagList.get(ThreadLocalRandom.current().nextInt(user.tagList.size()))) // Random tag
+ .param("language", "eng")
+ .param("create_date", Long.toString(createDate));
+ JsonObject json = resource.path("/document").request()
+ .cookie(TokenBasedSecurityFilter.COOKIE_NAME, user.authToken)
+ .put(Entity.form(form), JsonObject.class);
+ String documentId = json.getString("id");
log.info("Created document " + (documentCreatedCount++) + "/" + DOCUMENT_PER_USER_COUNT * USER_COUNT + " for user: " + user.username);
// Add files for each document
for (int j = 0; j < FILE_PER_DOCUMENT_COUNT; j++) {
- WebResource fileResource = resource.path("/file");
- fileResource.addFilter(new CookieAuthenticationFilter(user.authToken));
- FormDataMultiPart form = new FormDataMultiPart();
- InputStream file = Main.class.getResourceAsStream("/empty.png");
- FormDataBodyPart fdp = new FormDataBodyPart("file",
- new BufferedInputStream(file),
- MediaType.APPLICATION_OCTET_STREAM_TYPE);
- form.bodyPart(fdp);
- form.field("id", documentId);
- response = fileResource.type(MediaType.MULTIPART_FORM_DATA).put(ClientResponse.class, form);
- Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
+ try (InputStream is = Resources.getResource("empty.png").openStream()) {
+ StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "empty.png");
+ @SuppressWarnings("resource")
+ ClientResponse response = resource
+ .register(MultiPartFeature.class)
+ .path("/file").request()
+ .cookie(TokenBasedSecurityFilter.COOKIE_NAME, user.authToken)
+ .put(Entity.entity(new FormDataMultiPart().field("id", documentId).bodyPart(streamDataBodyPart),
+ MediaType.MULTIPART_FORM_DATA_TYPE), ClientResponse.class);
+ Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
+ }
}
}
}
diff --git a/docs-web-common/pom.xml b/docs-web-common/pom.xml
index 77072436..38df767c 100644
--- a/docs-web-common/pom.xml
+++ b/docs-web-common/pom.xml
@@ -22,23 +22,13 @@
- com.sun.jersey
- jersey-server
+ org.glassfish.jersey.containers
+ jersey-container-servlet
-
+
- com.sun.jersey
- jersey-bundle
-
-
-
- com.sun.jersey
- jersey-json
-
-
-
- com.sun.jersey.contribs
- jersey-multipart
+ org.glassfish.jersey.media
+ jersey-media-json-processing
@@ -68,8 +58,8 @@
- org.mortbay.jetty
- servlet-api
+ javax.servlet
+ javax.servlet-api
provided
@@ -86,14 +76,20 @@
- com.sun.grizzly
- grizzly-servlet-webserver
+ org.glassfish.jersey.test-framework.providers
+ jersey-test-framework-provider-external
test
-
+
- com.sun.jersey.jersey-test-framework
- jersey-test-framework-grizzly2
+ org.glassfish.jersey.test-framework.providers
+ jersey-test-framework-provider-grizzly2
+ test
+
+
+
+ org.glassfish.jersey.containers
+ jersey-container-grizzly2-servlet
test
diff --git a/docs-web-common/src/main/java/com/sismics/rest/exception/ClientException.java b/docs-web-common/src/main/java/com/sismics/rest/exception/ClientException.java
index 23f75ec8..9a1a233d 100644
--- a/docs-web-common/src/main/java/com/sismics/rest/exception/ClientException.java
+++ b/docs-web-common/src/main/java/com/sismics/rest/exception/ClientException.java
@@ -1,11 +1,9 @@
package com.sismics.rest.exception;
-
-import org.codehaus.jettison.json.JSONException;
-import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.json.Json;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@@ -32,9 +30,8 @@ public class ClientException extends WebApplicationException {
* @param type Error type (e.g. AlreadyExistingEmail, ValidationError)
* @param message Human readable error message
* @param e Readable error message
- * @throws JSONException
*/
- public ClientException(String type, String message, Exception e) throws JSONException {
+ public ClientException(String type, String message, Exception e) {
this(type, message);
log.error(type + ": " + message, e);
}
@@ -44,11 +41,10 @@ public class ClientException extends WebApplicationException {
*
* @param type Error type (e.g. AlreadyExistingEmail, ValidationError)
* @param message Human readable error message
- * @throws JSONException
*/
- public ClientException(String type, String message) throws JSONException {
- super(Response.status(Status.BAD_REQUEST).entity(new JSONObject()
- .put("type", type)
- .put("message", message)).build());
+ public ClientException(String type, String message) {
+ super(Response.status(Status.BAD_REQUEST).entity(Json.createObjectBuilder()
+ .add("type", type)
+ .add("message", message).build()).build());
}
}
diff --git a/docs-web-common/src/main/java/com/sismics/rest/exception/ForbiddenClientException.java b/docs-web-common/src/main/java/com/sismics/rest/exception/ForbiddenClientException.java
index 86786d38..7f92b32b 100644
--- a/docs-web-common/src/main/java/com/sismics/rest/exception/ForbiddenClientException.java
+++ b/docs-web-common/src/main/java/com/sismics/rest/exception/ForbiddenClientException.java
@@ -1,8 +1,6 @@
package com.sismics.rest.exception;
-import org.codehaus.jettison.json.JSONException;
-import org.codehaus.jettison.json.JSONObject;
-
+import javax.json.Json;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@@ -20,12 +18,10 @@ public class ForbiddenClientException extends WebApplicationException {
/**
* Constructor of ForbiddenClientException.
- *
- * @throws JSONException
*/
- public ForbiddenClientException() throws JSONException {
- super(Response.status(Status.FORBIDDEN).entity(new JSONObject()
- .put("type", "ForbiddenError")
- .put("message", "You don't have access to this resource")).build());
+ public ForbiddenClientException() {
+ super(Response.status(Status.FORBIDDEN).entity(Json.createObjectBuilder()
+ .add("type", "ForbiddenError")
+ .add("message", "You don't have access to this resource").build()).build());
}
}
diff --git a/docs-web-common/src/main/java/com/sismics/rest/exception/ServerException.java b/docs-web-common/src/main/java/com/sismics/rest/exception/ServerException.java
index a2947260..76b80d47 100644
--- a/docs-web-common/src/main/java/com/sismics/rest/exception/ServerException.java
+++ b/docs-web-common/src/main/java/com/sismics/rest/exception/ServerException.java
@@ -1,14 +1,13 @@
package com.sismics.rest.exception;
-import org.codehaus.jettison.json.JSONException;
-import org.codehaus.jettison.json.JSONObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
+import javax.json.Json;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* Jersey exception encapsulating an error from the client (INTERNAL_SERVER_ERROR).
*
@@ -31,9 +30,8 @@ public class ServerException extends WebApplicationException {
* @param type Error type (e.g. DatabaseError)
* @param message Human readable error message
* @param e Inner exception
- * @throws JSONException
*/
- public ServerException(String type, String message, Exception e) throws JSONException {
+ public ServerException(String type, String message, Exception e) {
this(type, message);
log.error(type + ": " + message, e);
}
@@ -43,11 +41,10 @@ public class ServerException extends WebApplicationException {
*
* @param type Error type (e.g. DatabaseError)
* @param message Human readable error message
- * @throws JSONException
*/
- public ServerException(String type, String message) throws JSONException {
- super(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new JSONObject()
- .put("type", type)
- .put("message", message)).build());
+ public ServerException(String type, String message) {
+ super(Response.status(Status.INTERNAL_SERVER_ERROR).entity(Json.createObjectBuilder()
+ .add("type", type)
+ .add("message", message).build()).build());
}
}
diff --git a/docs-web-common/src/main/java/com/sismics/rest/resource/GenericExceptionMapper.java b/docs-web-common/src/main/java/com/sismics/rest/resource/GenericExceptionMapper.java
deleted file mode 100644
index 922368d2..00000000
--- a/docs-web-common/src/main/java/com/sismics/rest/resource/GenericExceptionMapper.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.sismics.rest.resource;
-
-import org.codehaus.jettison.json.JSONException;
-import org.codehaus.jettison.json.JSONObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-/**
- * Generic exception mapper that transforms all unknown exception into ServerError.
- *
- * @author jtremeaux
- */
-@Provider
-public class GenericExceptionMapper implements ExceptionMapper {
- /**
- * Logger.
- */
- private static final Logger log = LoggerFactory.getLogger(GenericExceptionMapper.class);
-
- @Override
- public Response toResponse(Exception e) {
- if (e instanceof WebApplicationException) {
- return ((WebApplicationException) e).getResponse();
- }
-
- log.error("Unknown error", e);
-
- JSONObject entity = new JSONObject();
- try {
- entity.put("type", "UnknownError");
- entity.put("message", "Unknown server error");
- } catch (JSONException e2) {
- log.error("Error building response", e2);
- }
-
- return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
- .entity(entity)
- .build();
- }
-}
diff --git a/docs-web-common/src/main/java/com/sismics/rest/util/JsonUtil.java b/docs-web-common/src/main/java/com/sismics/rest/util/JsonUtil.java
index 7ba3b5da..a244ef1a 100644
--- a/docs-web-common/src/main/java/com/sismics/rest/util/JsonUtil.java
+++ b/docs-web-common/src/main/java/com/sismics/rest/util/JsonUtil.java
@@ -1,40 +1,38 @@
package com.sismics.rest.util;
-import org.codehaus.jettison.json.JSONArray;
-import org.codehaus.jettison.json.JSONException;
-import org.codehaus.jettison.json.JSONObject;
+import javax.json.Json;
+import javax.json.JsonValue;
/**
* JSON utilities.
*
- * @author jtremeaux
+ * @author bgamard
*/
public class JsonUtil {
+
+ /**
+ * Returns a JsonValue from a String.
+ *
+ * @param value Value
+ * @return JsonValue
+ */
+ public static JsonValue nullable(String value) {
+ if (value == null) {
+ return JsonValue.NULL;
+ }
+ return Json.createObjectBuilder().add("_", value).build().get("_");
+ }
/**
- * Fix of {@see JsonObject.append()}, which seems to create nested arrays.
+ * Returns a JsonValue from an Integer.
*
- * @param o JSON Object
- * @param key Key containing the array of null
- * @param value Value to append
- * @return Updated object
- * @throws JSONException
+ * @param value Value
+ * @return JsonValue
*/
- public static JSONObject append(JSONObject o, String key, JSONObject value) throws JSONException {
- Object prevValue = o.opt(key);
- if (prevValue == null) {
- o.put(key, new JSONArray().put(value));
- } else if (!(prevValue instanceof JSONArray)){
- throw new JSONException("JSONObject[" + key + "] is not a JSONArray.");
- } else {
- JSONArray newArray = new JSONArray();
- JSONArray oldArray = ((JSONArray) prevValue);
- for (int i = 0; i < oldArray.length(); i++) {
- newArray.put(oldArray.get(i));
- }
- newArray.put(value);
- o.put(key, newArray);
+ public static JsonValue nullable(Integer value) {
+ if (value == null) {
+ return JsonValue.NULL;
}
- return o;
+ return Json.createObjectBuilder().add("_", value).build().get("_");
}
}
diff --git a/docs-web-common/src/main/java/com/sismics/rest/util/ValidationUtil.java b/docs-web-common/src/main/java/com/sismics/rest/util/ValidationUtil.java
index f0f8f960..8bcea9ff 100644
--- a/docs-web-common/src/main/java/com/sismics/rest/util/ValidationUtil.java
+++ b/docs-web-common/src/main/java/com/sismics/rest/util/ValidationUtil.java
@@ -1,26 +1,22 @@
package com.sismics.rest.util;
-import com.google.common.base.Strings;
-import com.sismics.docs.core.dao.file.theme.ThemeDao;
-import com.sismics.docs.core.dao.jpa.LocaleDao;
-import com.sismics.docs.core.model.jpa.Locale;
-import com.sismics.rest.exception.ClientException;
-import org.apache.commons.lang.StringUtils;
-import org.codehaus.jettison.json.JSONException;
-import org.joda.time.DateTime;
-
import java.text.MessageFormat;
import java.util.Date;
-import java.util.List;
import java.util.regex.Pattern;
+import org.apache.commons.lang.StringUtils;
+import org.joda.time.DateTime;
+
+import com.google.common.base.Strings;
+import com.sismics.rest.exception.ClientException;
+
/**
* Utility class to validate parameters.
*
* @author jtremeaux
*/
public class ValidationUtil {
- private static Pattern EMAIL_PATTERN = Pattern.compile(".+@.+\\..+");
+ private static Pattern EMAIL_PATTERN = Pattern.compile(".+@.+");
private static Pattern HTTP_URL_PATTERN = Pattern.compile("https?://.+");
@@ -31,9 +27,9 @@ public class ValidationUtil {
*
* @param s Object tu validate
* @param name Name of the parameter
- * @throws JSONException
+ * @throws ClientException
*/
- public static void validateRequired(Object s, String name) throws JSONException {
+ public static void validateRequired(Object s, String name) throws ClientException {
if (s == null) {
throw new ClientException("ValidationError", MessageFormat.format("{0} must be set", name));
}
@@ -50,7 +46,7 @@ public class ValidationUtil {
* @return String without white spaces
* @throws ClientException
*/
- public static String validateLength(String s, String name, Integer lengthMin, Integer lengthMax, boolean nullable) throws JSONException {
+ public static String validateLength(String s, String name, Integer lengthMin, Integer lengthMax, boolean nullable) throws ClientException {
s = StringUtils.strip(s);
if (nullable && StringUtils.isEmpty(s)) {
return s;
@@ -62,7 +58,7 @@ public class ValidationUtil {
throw new ClientException("ValidationError", MessageFormat.format("{0} must be more than {1} characters", name, lengthMin));
}
if (lengthMax != null && s.length() > lengthMax) {
- throw new ClientException("ValidationError", MessageFormat.format("{0} must be less than {1} characters", name, lengthMax));
+ throw new ClientException("ValidationError", MessageFormat.format("{0} must be more than {1} characters", name, lengthMax));
}
return s;
}
@@ -77,7 +73,7 @@ public class ValidationUtil {
* @return String without white spaces
* @throws ClientException
*/
- public static String validateLength(String s, String name, Integer lengthMin, Integer lengthMax) throws JSONException {
+ public static String validateLength(String s, String name, Integer lengthMin, Integer lengthMax) throws ClientException {
return validateLength(s, name, lengthMin, lengthMax, false);
}
@@ -87,12 +83,25 @@ public class ValidationUtil {
* @param s String to validate
* @param name Name of the parameter
* @return String without white spaces
- * @throws JSONException
+ * @throws ClientException
*/
- public static String validateStringNotBlank(String s, String name) throws JSONException {
+ public static String validateStringNotBlank(String s, String name) throws ClientException {
return validateLength(s, name, 1, null, false);
}
+ /**
+ * Checks if the string is an email.
+ *
+ * @param s String to validate
+ * @param name Name of the parameter
+ * @throws ClientException
+ */
+ public static void validateEmail(String s, String name) throws ClientException {
+ if (!EMAIL_PATTERN.matcher(s).matches()) {
+ throw new ClientException("ValidationError", MessageFormat.format("{0} must be an email", name));
+ }
+ }
+
/**
* Checks if the string is a hexadecimal color.
*
@@ -101,32 +110,19 @@ public class ValidationUtil {
* @param nullable True if the string can be empty or null
* @throws JSONException
*/
- public static void validateHexColor(String s, String name, boolean nullable) throws JSONException {
+ public static void validateHexColor(String s, String name, boolean nullable) throws ClientException {
ValidationUtil.validateLength(s, "name", 7, 7, nullable);
}
- /**
- * Checks if the string is an email.
- *
- * @param s String to validate
- * @param name Name of the parameter
- * @throws JSONException
- */
- public static void validateEmail(String s, String name) throws JSONException {
- if (!EMAIL_PATTERN.matcher(s).matches()) {
- throw new ClientException("ValidationError", MessageFormat.format("{0} must be an email", name));
- }
- }
-
/**
* Validates that the provided string matches an URL with HTTP or HTTPS scheme.
*
* @param s String to validate
* @param name Name of the parameter
* @return Stripped URL
- * @throws JSONException
+ * @throws ClientException
*/
- public static String validateHttpUrl(String s, String name) throws JSONException {
+ public static String validateHttpUrl(String s, String name) throws ClientException {
s = StringUtils.strip(s);
if (!HTTP_URL_PATTERN.matcher(s).matches()) {
throw new ClientException("ValidationError", MessageFormat.format("{0} must be an HTTP(s) URL", name));
@@ -139,14 +135,30 @@ public class ValidationUtil {
*
* @param s String to validate
* @param name Name of the parameter
- * @throws JSONException
+ * @throws ClientException
*/
- public static void validateAlphanumeric(String s, String name) throws JSONException {
+ public static void validateAlphanumeric(String s, String name) throws ClientException {
if (!ALPHANUMERIC_PATTERN.matcher(s).matches()) {
throw new ClientException("ValidationError", MessageFormat.format("{0} must have only alphanumeric or underscore characters", name));
}
}
+ /**
+ * Checks if the string is a number.
+ *
+ * @param s String to validate
+ * @param name Name of the parameter
+ * @return Parsed number
+ * @throws ClientException
+ */
+ public static Integer validateInteger(String s, String name) throws ClientException {
+ try {
+ return Integer.valueOf(s);
+ } catch (NumberFormatException e) {
+ throw new ClientException("Validation Error", MessageFormat.format("{0} is not a number", name));
+ }
+ }
+
/**
* Validates and parses a date.
*
@@ -154,9 +166,9 @@ public class ValidationUtil {
* @param name Name of the parameter
* @param nullable True if the string can be empty or null
* @return Parsed date
- * @throws JSONException
+ * @throws ClientException
*/
- public static Date validateDate(String s, String name, boolean nullable) throws JSONException {
+ public static Date validateDate(String s, String name, boolean nullable) throws ClientException {
if (Strings.isNullOrEmpty(s)) {
if (!nullable) {
throw new ClientException("ValidationError", MessageFormat.format("{0} must be set", name));
@@ -170,56 +182,4 @@ public class ValidationUtil {
throw new ClientException("ValidationError", MessageFormat.format("{0} must be a date", name));
}
}
-
- /**
- * Validates a locale.
- *
- * @param localeId String to validate
- * @param name Name of the parameter
- * @return String without white spaces
- * @param nullable True if the string can be empty or null
- * @throws ClientException
- */
- public static String validateLocale(String localeId, String name, boolean nullable) throws JSONException {
- localeId = StringUtils.strip(localeId);
- if (StringUtils.isEmpty(localeId)) {
- if (!nullable) {
- throw new ClientException("ValidationError", MessageFormat.format("{0} is required", name));
- } else {
- return null;
- }
- }
- LocaleDao localeDao = new LocaleDao();
- Locale locale = localeDao.getById(localeId);
- if (locale == null) {
- throw new ClientException("ValidationError", "Locale not found: " + localeId);
- }
- return localeId;
- }
-
- /**
- * Validates a theme.
- *
- * @param themeId ID of the theme to validate
- * @param name Name of the parameter
- * @return String without white spaces
- * @param nullable True if the string can be empty or null
- * @throws ClientException
- */
- public static String validateTheme(String themeId, String name, boolean nullable) throws JSONException {
- themeId = StringUtils.strip(themeId);
- if (StringUtils.isEmpty(themeId)) {
- if (!nullable) {
- throw new ClientException("ValidationError", MessageFormat.format("{0} is required", name));
- } else {
- return null;
- }
- }
- ThemeDao themeDao = new ThemeDao();
- List themeList = themeDao.findAll();
- if (!themeList.contains(themeId)) {
- throw new ClientException("ValidationError", "Theme not found: " + themeId);
- }
- return themeId;
- }
}
diff --git a/docs-web-common/src/main/java/com/sismics/util/filter/RequestContextFilter.java b/docs-web-common/src/main/java/com/sismics/util/filter/RequestContextFilter.java
index c10ab7fb..145c4c8b 100644
--- a/docs-web-common/src/main/java/com/sismics/util/filter/RequestContextFilter.java
+++ b/docs-web-common/src/main/java/com/sismics/util/filter/RequestContextFilter.java
@@ -38,11 +38,10 @@ public class RequestContextFilter implements Filter {
// Force the locale in order to not depend on the execution environment
Locale.setDefault(new Locale(Constants.DEFAULT_LOCALE_ID));
- // Injects the webapp root
- String webappRoot = filterConfig.getServletContext().getRealPath("/");
- EnvironmentUtil.setWebappRoot(webappRoot);
-
// Initialize the app directory
+ if (!filterConfig.getServletContext().getServerInfo().startsWith("Grizzly")) {
+ EnvironmentUtil.setWebappContext(true);
+ }
File baseDataDirectory = null;
try {
baseDataDirectory = DirectoryUtil.getBaseDataDirectory();
diff --git a/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java b/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java
index 2a526577..80fc4fb9 100644
--- a/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java
+++ b/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java
@@ -1,16 +1,27 @@
package com.sismics.docs.rest;
import java.io.File;
+import java.net.URI;
import java.net.URLDecoder;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.UriBuilder;
+
import org.glassfish.grizzly.http.server.HttpServer;
-import org.glassfish.grizzly.http.server.StaticHttpHandler;
+import org.glassfish.grizzly.servlet.ServletRegistration;
+import org.glassfish.grizzly.servlet.WebappContext;
+import org.glassfish.jersey.servlet.ServletContainer;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.glassfish.jersey.test.external.ExternalTestContainerFactory;
+import org.glassfish.jersey.test.spi.TestContainerException;
+import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.After;
import org.junit.Before;
-import com.sismics.docs.rest.descriptor.JerseyTestWebAppDescriptorFactory;
import com.sismics.docs.rest.util.ClientUtil;
-import com.sun.jersey.test.framework.JerseyTest;
+import com.sismics.util.filter.RequestContextFilter;
+import com.sismics.util.filter.TokenBasedSecurityFilter;
/**
* Base class of integration tests with Jersey.
@@ -28,12 +39,21 @@ public abstract class BaseJerseyTest extends JerseyTest {
*/
protected ClientUtil clientUtil;
- /**
- * Constructor of BaseJerseyTest.
- */
- public BaseJerseyTest() {
- super(JerseyTestWebAppDescriptorFactory.build());
- this.clientUtil = new ClientUtil(resource());
+ @Override
+ protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
+ return new ExternalTestContainerFactory();
+ }
+
+ @Override
+ protected Application configure() {
+ enable(TestProperties.LOG_TRAFFIC);
+ enable(TestProperties.DUMP_ENTITY);
+ return new Application();
+ }
+
+ @Override
+ protected URI getBaseUri() {
+ return UriBuilder.fromUri(super.getBaseUri()).path("docs").build();
}
@Override
@@ -41,10 +61,23 @@ public abstract class BaseJerseyTest extends JerseyTest {
public void setUp() throws Exception {
super.setUp();
+ clientUtil = new ClientUtil(target());
+
String httpRoot = URLDecoder.decode(new File(getClass().getResource("/").getFile()).getAbsolutePath(), "utf-8");
- httpServer = HttpServer.createSimpleServer(httpRoot, "localhost", 9997);
- // Disable file cache to fix https://java.net/jira/browse/GRIZZLY-1350
- ((StaticHttpHandler) httpServer.getServerConfiguration().getHttpHandlers().keySet().iterator().next()).setFileCacheEnabled(false);
+ httpServer = HttpServer.createSimpleServer(httpRoot, "localhost", getPort());
+ WebappContext context = new WebappContext("GrizzlyContext", "/docs");
+ context.addFilter("requestContextFilter", RequestContextFilter.class)
+ .addMappingForUrlPatterns(null, "/*");
+ context.addFilter("tokenBasedSecurityFilter", TokenBasedSecurityFilter.class)
+ .addMappingForUrlPatterns(null, "/*");
+ ServletRegistration reg = context.addServlet("jerseyServlet", ServletContainer.class);
+ reg.setInitParameter("jersey.config.server.provider.packages", "com.sismics.docs.rest.resource");
+ reg.setInitParameter("jersey.config.server.provider.classnames", "org.glassfish.jersey.media.multipart.MultiPartFeature");
+ reg.setInitParameter("jersey.config.server.response.setStatusOverSendError", "true");
+ reg.setLoadOnStartup(1);
+ reg.addMapping("/*");
+ reg.setAsyncSupported(true);
+ context.deploy(httpServer);
httpServer.start();
}
@@ -52,6 +85,8 @@ public abstract class BaseJerseyTest extends JerseyTest {
@After
public void tearDown() throws Exception {
super.tearDown();
- httpServer.stop();
+ if (httpServer != null) {
+ httpServer.shutdownNow();
+ }
}
}
diff --git a/docs-web-common/src/test/java/com/sismics/docs/rest/descriptor/JerseyTestWebAppDescriptorFactory.java b/docs-web-common/src/test/java/com/sismics/docs/rest/descriptor/JerseyTestWebAppDescriptorFactory.java
deleted file mode 100644
index eac35dcd..00000000
--- a/docs-web-common/src/test/java/com/sismics/docs/rest/descriptor/JerseyTestWebAppDescriptorFactory.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.sismics.docs.rest.descriptor;
-
-import com.sismics.util.filter.RequestContextFilter;
-import com.sismics.util.filter.TokenBasedSecurityFilter;
-import com.sun.jersey.test.framework.WebAppDescriptor;
-
-import java.io.File;
-
-/**
- * Jersey tests Webapp descriptor.
- *
- * @author jtremeaux
- */
-public class JerseyTestWebAppDescriptorFactory {
- private static String basePath = new File("src/main/webapp").getAbsolutePath();
-
- /**
- * Constructs a new descriptor.
- *
- * @return Descriptor
- */
- public static WebAppDescriptor build() {
- // Target the base path to the Webapp resources
- System.setProperty("user.dir", basePath);
- System.setProperty("test", "true");
-
- return new WebAppDescriptor.Builder("com.sismics.docs.rest.resource")
- .contextPath("docs")
- .addFilter(RequestContextFilter.class, "requestContextFilter")
- .addFilter(TokenBasedSecurityFilter.class, "tokenBasedSecurityFilter")
- .initParam("com.sun.jersey.spi.container.ContainerRequestFilters", "com.sun.jersey.api.container.filter.LoggingFilter")
- .initParam("com.sun.jersey.spi.container.ContainerResponseFilters", "com.sun.jersey.api.container.filter.LoggingFilter")
- .initParam("com.sun.jersey.config.feature.logging.DisableEntitylogging", "true")
- .build();
- }
-}
diff --git a/docs-web-common/src/test/java/com/sismics/docs/rest/filter/CookieAuthenticationFilter.java b/docs-web-common/src/test/java/com/sismics/docs/rest/filter/CookieAuthenticationFilter.java
deleted file mode 100644
index 699829a4..00000000
--- a/docs-web-common/src/test/java/com/sismics/docs/rest/filter/CookieAuthenticationFilter.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.sismics.docs.rest.filter;
-
-import com.sismics.util.filter.TokenBasedSecurityFilter;
-import com.sun.jersey.api.client.ClientHandlerException;
-import com.sun.jersey.api.client.ClientRequest;
-import com.sun.jersey.api.client.ClientResponse;
-import com.sun.jersey.api.client.filter.ClientFilter;
-
-import javax.ws.rs.core.Cookie;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Filter to add the authentication token into a cookie.
- *
- * @author jtremeaux
- */
-public class CookieAuthenticationFilter extends ClientFilter {
- private String authToken;
-
- public CookieAuthenticationFilter(String authToken) {
- this.authToken = authToken;
- }
-
- @Override
- public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
- Cookie cookie = new Cookie(TokenBasedSecurityFilter.COOKIE_NAME, authToken);
- List