Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
*.iml
target
/env.bat
16 changes: 16 additions & 0 deletions src/main/java/fr/ybonnel/simpleweb4j/SimpleWeb4j.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.handler.AbstractHandler;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -240,6 +242,20 @@ public static void stop() {
started = false;
}

/**
* Adds the routes defined in the specified input stream. Each route is defined by a line with the following format:
*
* [HttpMethod] [ParamType] [routePath] [controllerMethod]\n
*
* @param inputStream Input that contains the route definitions.
* @throws NoSuchMethodException If the controller method does not exist.
* @throws IOException If an I/O error occurs
* @throws ClassNotFoundException In the controller class does not exist.
*/
public static void loadRoutes(InputStream inputStream) throws NoSuchMethodException, IOException, ClassNotFoundException {
jsonHandler.loadRoutes(inputStream);
}

/**
* Add a new route for GET method.
* Use :
Expand Down
47 changes: 44 additions & 3 deletions src/main/java/fr/ybonnel/simpleweb4j/handlers/JsonHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
import fr.ybonnel.simpleweb4j.exception.HttpErrorException;
import fr.ybonnel.simpleweb4j.handlers.filter.AbstractFilter;
import fr.ybonnel.simpleweb4j.model.SimpleEntityManager;
import fr.ybonnel.simpleweb4j.router.ControllerRoute;
import fr.ybonnel.simpleweb4j.util.StringUtils;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
Expand Down Expand Up @@ -62,6 +62,47 @@ public class JsonHandler extends AbstractHandler {
*/
private Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXX").create();

/**
*
* @param inputStream
* @throws IOException
* @throws NoSuchMethodException
* @throws ClassNotFoundException
*/
public void loadRoutes(InputStream inputStream) throws IOException, NoSuchMethodException, ClassNotFoundException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while ((line = reader.readLine()) != null){
HttpMethod httpMethod = null;
Class<?> paramType = null;
String routePath = null;
String controller = null;

// Read Http Method
line = line.trim();
int firstBlankCharacterIndex = StringUtils.getIndexOfBlank(line);
httpMethod = HttpMethod.valueOf(line.substring(0, firstBlankCharacterIndex).toUpperCase());

// Read Parameter type
line = line.substring(firstBlankCharacterIndex).trim();
firstBlankCharacterIndex = StringUtils.getIndexOfBlank(line);
paramType = Class.forName(line.substring(0, firstBlankCharacterIndex));

// Read route routePath
line = line.substring(firstBlankCharacterIndex).trim();
firstBlankCharacterIndex = StringUtils.getIndexOfBlank(line);
routePath = line.substring(0, firstBlankCharacterIndex);

// Read controller method
line = line.substring(firstBlankCharacterIndex).trim();
controller = line;

// Create and add route.
ControllerRoute<?,?> route = new ControllerRoute(routePath, paramType, controller);
addRoute(httpMethod, route);
}

}
/**
* Add a route.
* @param httpMethod http method of the route.
Expand Down
68 changes: 68 additions & 0 deletions src/main/java/fr/ybonnel/simpleweb4j/router/ControllerRoute.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package fr.ybonnel.simpleweb4j.router;

import fr.ybonnel.simpleweb4j.exception.HttpErrorException;
import fr.ybonnel.simpleweb4j.handlers.Response;
import fr.ybonnel.simpleweb4j.handlers.Route;
import fr.ybonnel.simpleweb4j.handlers.RouteParameters;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
*/
public class ControllerRoute<P, R> extends Route<P, R> {

/** Controller method. */
private Method controllerMethod;

/**
* Constructor of a route.
*
* @param routePath routePath of the route.
* @param paramType class of the object in request's body.
*/
public ControllerRoute(String routePath, Class<P> paramType, String controller) throws ClassNotFoundException, NoSuchMethodException {
super(routePath, paramType);

int lastDotIndex = controller.lastIndexOf(".");
if (lastDotIndex < 1) {
throw new IllegalArgumentException("Controller param is not a controller method.");
}
String controllerClassName = controller.substring(0, lastDotIndex);
String controllerMethodName = controller.substring(lastDotIndex + 1);

Class<?> controllerClass = Class.forName(controllerClassName);

if (Void.class.equals(paramType)) {
controllerMethod = controllerClass.getMethod(controllerMethodName, RouteParameters.class);
}
else {
controllerMethod = controllerClass.getMethod(controllerMethodName, paramType, RouteParameters.class);
}
}

/**
* Invokes the controller static method to compute the HTTP Response.
*
* @param param the parameter object in request's body.
* @param routeParams parameters in the routePath.
* @return The request response.
* @throws HttpErrorException If an error occured.
*/
@Override
public Response<R> handle(P param, RouteParameters routeParams) throws HttpErrorException {
try {
R result = null;
if (Void.class.equals(getParamType())) {
result = (R) controllerMethod.invoke(null, routeParams);
}
else {
result = (R) controllerMethod.invoke(null, param, routeParams);
}
return new Response<R>(result);
} catch (Exception e) {
e.printStackTrace();
throw new HttpErrorException(500, e);
}
}
}
25 changes: 25 additions & 0 deletions src/main/java/fr/ybonnel/simpleweb4j/util/StringUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package fr.ybonnel.simpleweb4j.util;

/**
*/
public class StringUtils {

public static int getIndexOfBlank(String value) {
if (value == null) {
return -1;
}
int firstSpaceIndex = value.indexOf(' ');
if (firstSpaceIndex < 0) {
firstSpaceIndex = Integer.MAX_VALUE;
}
int firstTabIndex = value.indexOf('\t');
if (firstTabIndex < 0) {
firstTabIndex = Integer.MAX_VALUE;
}
int firstBlankCharacterIndex = Math.min(firstSpaceIndex, firstTabIndex);
if (firstBlankCharacterIndex == Integer.MAX_VALUE) {
firstBlankCharacterIndex = -1;
}
return firstBlankCharacterIndex;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@
import fr.ybonnel.simpleweb4j.entities.SimpleEntity;
import fr.ybonnel.simpleweb4j.exception.HttpErrorException;
import fr.ybonnel.simpleweb4j.model.SimpleEntityManager;
import fr.ybonnel.simpleweb4j.router.ControllerRoute;
import org.eclipse.jetty.server.Request;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Enumeration;
Expand All @@ -48,6 +51,38 @@ public void setup() {
setEntitiesClasses();
}

@Test
public void testLoadRoutes() throws NoSuchMethodException, IOException, ClassNotFoundException {
InputStream inputStream = null;

try {
inputStream = getClass().getResourceAsStream("/fr/ybonnel/simpleweb4j/routes");
handler.loadRoutes(inputStream);

Route route = handler.findRoute("GET", "/test/empty");
Assert.assertNotNull(route);
Assert.assertTrue(route instanceof ControllerRoute);

route = handler.findRoute("POST", "/test/integer");
Assert.assertNotNull(route);
Assert.assertTrue(route instanceof ControllerRoute);

route = handler.findRoute("PUT", "/test/string");
Assert.assertNotNull(route);
Assert.assertTrue(route instanceof ControllerRoute);

route = handler.findRoute("DELETE", "/test/delete/long");
Assert.assertNotNull(route);
Assert.assertTrue(route instanceof ControllerRoute);
}
finally {
if (inputStream != null) {
try { inputStream.close(); }
catch (Exception e) {}
}
}
}

@Test
public void testHandleAlreadyHandle() throws IOException, ServletException {
Request request = mock(Request.class);
Expand Down
21 changes: 14 additions & 7 deletions src/test/java/fr/ybonnel/simpleweb4j/samples/forms/Forms.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,34 @@
import fr.ybonnel.simpleweb4j.handlers.RouteParameters;
import fr.ybonnel.simpleweb4j.samples.forms.model.Countries;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import static fr.ybonnel.simpleweb4j.SimpleWeb4j.*;

public class Forms {

public static void startServer(int port) {
public static void startServer(int port) throws Exception {
setPort(port);
setPublicResourcesPath("/fr/ybonnel/simpleweb4j/samples/forms/public");

get(new Route<Void, List<String>>("countries", Void.class) {
@Override
public Response<List<String>> handle(Void param, RouteParameters routeParams) throws HttpErrorException {
return new Response<>(Countries.list());
InputStream inputStream = null;
try {
inputStream = Forms.class.getResourceAsStream("/fr/ybonnel/simpleweb4j/samples/forms/routes");
loadRoutes(inputStream);
}
finally {
if (inputStream != null) {
try { inputStream.close(); }
catch (Exception e) { }
}
});
}

start();
}

public static void main(String[] args) {
public static void main(String[] args) throws Exception {
startServer(9999);

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package fr.ybonnel.simpleweb4j.samples.forms.controllers;

import fr.ybonnel.simpleweb4j.handlers.Response;
import fr.ybonnel.simpleweb4j.handlers.RouteParameters;
import fr.ybonnel.simpleweb4j.samples.forms.model.Countries;

import java.util.List;

/**
*/
public class CountryController {

public static List<String> getAll(RouteParameters routeParameters) {
return Countries.list();
}
}
21 changes: 21 additions & 0 deletions src/test/java/fr/ybonnel/simpleweb4j/util/StringUtilsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package fr.ybonnel.simpleweb4j.util;

import org.junit.Assert;
import org.junit.Test;

/**
*/
public class StringUtilsTest {

@Test
public void testGetIndexOfBlank() {
int index = StringUtils.getIndexOfBlank("test t");
Assert.assertEquals(4, index);

index = StringUtils.getIndexOfBlank("test\tt");
Assert.assertEquals(4, index);

index = StringUtils.getIndexOfBlank("test");
Assert.assertEquals(-1, index);
}
}
25 changes: 25 additions & 0 deletions src/test/java/test/TestController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package test;

import fr.ybonnel.simpleweb4j.handlers.RouteParameters;

/**
*/
public class TestController {

public static Object testEmpty(RouteParameters routeParameters) {
return null;
}

public static Object testInteger(Integer param, RouteParameters routeParameters) {
return null;
}

public static Object testString(String param, RouteParameters routeParameters) {
return null;
}

public static Object testDeleteLong(Long param, RouteParameters routeParameters) {
return null;
}

}
4 changes: 4 additions & 0 deletions src/test/resources/fr/ybonnel/simpleweb4j/routes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
GET java.lang.Void /test/empty test.TestController.testEmpty
POST java.lang.Integer /test/integer test.TestController.testInteger
PUT java.lang.String /test/string test.TestController.testString
DELETE java.lang.Long /test/delete/long test.TestController.testDeleteLong
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GET java.lang.Void countries fr.ybonnel.simpleweb4j.samples.forms.controllers.CountryController.getAll