mirror of
https://github.com/sismics/docs.git
synced 2025-12-13 01:36:18 +00:00
Closes #29: Upgrade to Jersey 2
This commit is contained in:
@@ -22,23 +22,13 @@
|
||||
|
||||
<!-- Dependencies to Jersey -->
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-server</artifactId>
|
||||
<groupId>org.glassfish.jersey.containers</groupId>
|
||||
<artifactId>jersey-container-servlet</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-bundle</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-multipart</artifactId>
|
||||
<groupId>org.glassfish.jersey.media</groupId>
|
||||
<artifactId>jersey-media-json-processing</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Other external dependencies -->
|
||||
@@ -68,8 +58,8 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -86,14 +76,20 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.grizzly</groupId>
|
||||
<artifactId>grizzly-servlet-webserver</artifactId>
|
||||
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
|
||||
<artifactId>jersey-test-framework-provider-external</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.jersey-test-framework</groupId>
|
||||
<artifactId>jersey-test-framework-grizzly2</artifactId>
|
||||
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
|
||||
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.containers</groupId>
|
||||
<artifactId>jersey-container-grizzly2-servlet</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Exception> {
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -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("_");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> themeList = themeDao.findAll();
|
||||
if (!themeList.contains(themeId)) {
|
||||
throw new ClientException("ValidationError", "Theme not found: " + themeId);
|
||||
}
|
||||
return themeId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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<Object> cookieList = new ArrayList<Object>();
|
||||
cookieList.add(cookie);
|
||||
if (authToken != null) {
|
||||
request.getHeaders().put("Cookie", cookieList);
|
||||
}
|
||||
ClientResponse response = getNext().handle(request);
|
||||
if (response.getCookies() != null) {
|
||||
cookieList.addAll(response.getCookies());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
package com.sismics.docs.rest.util;
|
||||
|
||||
import com.sismics.docs.rest.filter.CookieAuthenticationFilter;
|
||||
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
||||
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 junit.framework.Assert;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.json.JsonObject;
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.Form;
|
||||
import javax.ws.rs.core.NewCookie;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
||||
|
||||
/**
|
||||
* REST client utilities.
|
||||
@@ -17,14 +15,14 @@ import javax.ws.rs.core.NewCookie;
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ClientUtil {
|
||||
private WebResource resource;
|
||||
private WebTarget resource;
|
||||
|
||||
/**
|
||||
* Constructor of ClientUtil.
|
||||
*
|
||||
* @param webResource Resource corresponding to the base URI of REST resources.
|
||||
* @param resource Resource corresponding to the base URI of REST resources.
|
||||
*/
|
||||
public ClientUtil(WebResource resource) {
|
||||
public ClientUtil(WebTarget resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
@@ -38,15 +36,14 @@ public class ClientUtil {
|
||||
String adminAuthenticationToken = login("admin", "admin", false);
|
||||
|
||||
// Create the user
|
||||
WebResource userResource = resource.path("/user");
|
||||
userResource.addFilter(new CookieAuthenticationFilter(adminAuthenticationToken));
|
||||
MultivaluedMap<String, String> postParams = new MultivaluedMapImpl();
|
||||
postParams.putSingle("username", username);
|
||||
postParams.putSingle("email", username + "@docs.com");
|
||||
postParams.putSingle("password", "12345678");
|
||||
postParams.putSingle("time_zone", "Asia/Tokyo");
|
||||
ClientResponse response = userResource.put(ClientResponse.class, postParams);
|
||||
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||
Form form = new Form();
|
||||
form.param("username", username);
|
||||
form.param("email", username + "@docs.com");
|
||||
form.param("password", "12345678");
|
||||
form.param("time_zone", "Asia/Tokyo");
|
||||
resource.path("/user").request()
|
||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminAuthenticationToken)
|
||||
.put(Entity.form(form), JsonObject.class);
|
||||
|
||||
// Logout admin
|
||||
logout(adminAuthenticationToken);
|
||||
@@ -61,13 +58,12 @@ public class ClientUtil {
|
||||
* @return Authentication token
|
||||
*/
|
||||
public String login(String username, String password, Boolean remember) {
|
||||
WebResource userResource = resource.path("/user/login");
|
||||
MultivaluedMap<String, String> postParams = new MultivaluedMapImpl();
|
||||
postParams.putSingle("username", username);
|
||||
postParams.putSingle("password", password);
|
||||
postParams.putSingle("remember", remember.toString());
|
||||
ClientResponse response = userResource.post(ClientResponse.class, postParams);
|
||||
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||
Form form = new Form();
|
||||
form.param("username", username);
|
||||
form.param("password", password);
|
||||
form.param("remember", remember.toString());
|
||||
Response response = resource.path("/user/login").request()
|
||||
.post(Entity.form(form));
|
||||
|
||||
return getAuthenticationCookie(response);
|
||||
}
|
||||
@@ -88,10 +84,9 @@ public class ClientUtil {
|
||||
* @param authenticationToken Authentication token
|
||||
*/
|
||||
public void logout(String authenticationToken) {
|
||||
WebResource userResource = resource.path("/user/logout");
|
||||
userResource.addFilter(new CookieAuthenticationFilter(authenticationToken));
|
||||
ClientResponse response = userResource.post(ClientResponse.class);
|
||||
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||
resource.path("/user/logout").request()
|
||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, authenticationToken)
|
||||
.post(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,9 +95,9 @@ public class ClientUtil {
|
||||
* @param response Response
|
||||
* @return Authentication token
|
||||
*/
|
||||
public String getAuthenticationCookie(ClientResponse response) {
|
||||
public String getAuthenticationCookie(Response response) {
|
||||
String authToken = null;
|
||||
for (NewCookie cookie : response.getCookies()) {
|
||||
for (NewCookie cookie : response.getCookies().values()) {
|
||||
if (TokenBasedSecurityFilter.COOKIE_NAME.equals(cookie.getName())) {
|
||||
authToken = cookie.getValue();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user