Skip to content

Commit

Permalink
Improve ServerResponse performance.
Browse files Browse the repository at this point in the history
  • Loading branch information
noboomu committed Apr 11, 2017
1 parent 501c4d4 commit a0c5cd5
Show file tree
Hide file tree
Showing 11 changed files with 436 additions and 145 deletions.
99 changes: 48 additions & 51 deletions src/main/java/com/wurrly/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@
import com.google.common.util.concurrent.ServiceManager;
import com.google.common.util.concurrent.ServiceManager.Listener;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.j256.simplemagic.ContentType;
import com.jsoniter.any.Any;
import com.jsoniter.output.JsonStream;
import com.google.inject.name.Named;
import com.typesafe.config.Config;
import com.wurrly.controllers.Users;
import com.wurrly.modules.ConfigModule;
Expand All @@ -33,12 +32,12 @@

import io.undertow.Undertow;
import io.undertow.UndertowOptions;
import io.undertow.server.DefaultResponseListener;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.RoutingHandler;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.undertow.util.StatusCodes;
/**
* @author jbauer
*/
Expand Down Expand Up @@ -67,13 +66,25 @@ public static void notFoundHandler(HttpServerExchange exchange) {
protected Injector injector = null;
protected ServiceManager serviceManager = null;
protected Undertow webServer = null;

protected Set<Class<? extends Service>> registeredServices = new HashSet<>();

@Inject
@Named("registeredControllers")
protected Set<Class<?>> registeredControllers;

@Inject
@Named("registeredEndpoints")
protected Set<EndpointInfo> registeredEndpoints;

protected RoutingModule routingModule = null;

public Application()
{
this.routingModule = new RoutingModule();
injector = Guice.createInjector(new ConfigModule(),this.routingModule);

injector = Guice.createInjector(new ConfigModule());
injector.injectMembers(this);

}

public void start()
Expand Down Expand Up @@ -115,33 +126,33 @@ public void failure(Service service)

public Undertow buildServer()
{
Config rootConfig = injector.getInstance(Config.class);
RoutingHandler router = injector.getInstance(RoutingHandler.class);
RoutingModule routingModule = injector.getInstance(RoutingModule.class);

final Config rootConfig = injector.getInstance(Config.class);

final RoutingHandler router = injector.getInstance(RoutingHandler.class);

HandlerGenerator generator = new HandlerGenerator("com.wurrly.controllers.handlers","RouteHandlers",routingModule.getRegisteredControllers());
final DefaultResponseListener defaultResponseListener = injector.getInstance(DefaultResponseListener.class);

HandlerGenerator generator = new HandlerGenerator("com.wurrly.controllers.handlers","RouteHandlers",this.registeredControllers);

injector.injectMembers(generator);

Supplier<RoutingHandler> generatedRouteSupplier = injector.getInstance(generator.compileClass());

router.addAll(generatedRouteSupplier.get());

Supplier<RoutingHandler> benchmarkRouteSupplier = new BenchmarkHandlers();

router.addAll(benchmarkRouteSupplier.get());

router.addAll(new BenchmarkHandlers().get());

StringBuilder sb = new StringBuilder();

Set<EndpointInfo> routingInfo = routingModule.getRegisteredEndpoints(); //injector.getInstance(Key.get(new TypeLiteral<Set<RouteInfo>>() {},Names.named("routeInfo")));

routingInfo.stream().forEachOrdered( r -> sb.append(r.toString()).append("\n"));

this.registeredEndpoints.stream().forEachOrdered( r -> sb.append(r.toString()).append("\n"));

log.info("\n\nRegistered the following endpoints: \n\n" + sb.toString());

webServer = Undertow.builder()
.addHttpListener(rootConfig.getInt("application.port"), "localhost")
.setBufferSize(1024 * 16 * 10)
.setBufferSize(1024 * 16)
.setIoThreads(Runtime.getRuntime().availableProcessors())
.setServerOption(UndertowOptions.ENABLE_HTTP2, true)
.setServerOption(UndertowOptions.ALWAYS_SET_DATE, true)
Expand All @@ -155,56 +166,42 @@ public Undertow buildServer()
@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception
{
try
{
// if(exchange.isInIoThread())
// {
// exchange.dispatch(this);
// return;
// }

exchange.addDefaultResponseListener(defaultResponseListener);

exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Origin"), "*");
exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Methods"), "*");
exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Headers"), "*");
// exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Origin"), "*");
// exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Methods"), "*");
// exchange.getResponseHeaders().put(HttpString.tryFromString("Access-Control-Allow-Headers"), "*");
exchange.getResponseHeaders().put(Headers.SERVER, "Bowser");

router.handleRequest(exchange);

}
catch (IllegalArgumentException e)
{
if (exchange.isResponseChannelAvailable())
try {
router.handleRequest(exchange);
} catch (Exception e)
{
log.error(e.getMessage(),e);

exchange.setStatusCode(StatusCodes.BAD_REQUEST);
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, ContentType.JSON.getMimeType());
exchange.getResponseSender().send(JsonStream.serialize(Any.wrap(e)));

}
}
catch (Exception e)
{
if (exchange.isResponseChannelAvailable())
{
log.error(e.getMessage(),e);
if(exchange.isResponseChannelAvailable()) {
log.error(e.getMessage());
exchange.endExchange();
}
}
}
}
}).build();

return webServer;
}

public void useService(Class<? extends Service> serviceClass)
public Application useService(Class<? extends Service> serviceClass)
{
this.registeredServices.add(serviceClass);
return this;
}

public void useController(Class<?> controllerClass)
public Application useController(Class<?> controllerClass)
{
this.routingModule.getRegisteredControllers().add(controllerClass);
this.registeredControllers.add(controllerClass);
return this;
}


public static void main(String[] args)
{
Expand Down
36 changes: 22 additions & 14 deletions src/main/java/com/wurrly/controllers/Users.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@
import com.wurrly.models.User;
import com.wurrly.server.ServerRequest;
import com.wurrly.server.ServerResponse;
import static com.wurrly.server.ServerResponse.response;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.undertow.util.HttpString;
import io.undertow.util.StatusCodes;
import io.undertow.util.HttpString;
/**
* User API
*/
Expand Down Expand Up @@ -99,10 +99,10 @@ public ServerResponse userType(
log.debug("optionalDate: " + optionalDate);


return ServerResponse.builder()
return response()
.ok()
.withEntity(new User(232343L))
.withHeader(HttpString.tryFromString("TestHeader"), "57475475")
.entity(new User(232343L))
.header(HttpString.tryFromString("TestHeader"), "57475475")
.build();

}
Expand All @@ -111,7 +111,7 @@ public ServerResponse userType(
@Path("/form/{userId}")
@Consumes("*/*")
@ApiOperation(value = "Post a complex form", httpMethod = "POST", response = User.class)
public Any userForm(@ApiParam(hidden=true) final ServerRequest serverRequest,
public ServerResponse userForm(@ApiParam(hidden=true) final ServerRequest serverRequest,
@ApiParam(name="userId",required=true) @PathParam("userId") final Long userId,
@ApiParam(name="context",required=false) @QueryParam("context") Optional<String> context,
@ApiParam(name="type",required=true) @QueryParam("type") User.UserType type,
Expand All @@ -125,7 +125,7 @@ public Any userForm(@ApiParam(hidden=true) final ServerRequest serverRequest,
log.debug("testFile: " + testFile);
//
//
return Any.wrap(new User(userId,type));
return response().ok().entity(Any.wrap(new User(userId,type))).build();

}

Expand All @@ -145,10 +145,10 @@ public ServerResponse user(@ApiParam(hidden=true)final ServerRequest serverReque
// log.debug("context: " + context);
//
//
return ServerResponse.builder()
return response()
.ok()
.jsonType()
.withBody(JsonStream.serialize(new User(userId)))
.applicationJson()
.body(JsonStream.serialize(new User(userId)))
.build();


Expand All @@ -160,15 +160,23 @@ public ServerResponse user(@ApiParam(hidden=true)final ServerRequest serverReque
//@Consumes("multipart/form-data")
// @ApiImplicitParams({ @ApiImplicitParam(dataType = "com.wurrly.models.User", name = "user", paramType = "body", required = false, allowMultiple = false) })
@ApiOperation(value = "Create a user", httpMethod = "POST", response = User.class)
public Any createUser(@ApiParam(hidden=true)final ServerRequest serverRequest, @QueryParam("context") Optional<String> context, final User user )
public ServerResponse createUser(@ApiParam(hidden=true)final ServerRequest serverRequest, @QueryParam("context") Optional<String> context, final User user )
{
//

// log.debug("context: " + context);
// log.debug("request: " + serverRequest);
// log.debug("file: " + user);

return Any.wrap(new User(34L));

if( user != null )
{
return response().ok().entity(user).build();
}
else
{
return response().exception(new Exception("No user found")).build();
}



Expand All @@ -179,7 +187,7 @@ public Any createUser(@ApiParam(hidden=true)final ServerRequest serverRequest,
@Consumes(("application/json"))
// @ApiImplicitParams({ @ApiImplicitParam(dataType = "com.wurrly.models.User", name = "user", paramType = "body", required = false, allowMultiple = false) })
@ApiOperation(value = "Update a user's name", httpMethod = "PUT", response = User.class)
public Any updateUsername(@ApiParam(hidden=true)final ServerRequest serverRequest, @QueryParam("context") Optional<String> context, final User user )
public ServerResponse updateUsername(@ApiParam(hidden=true)final ServerRequest serverRequest, @QueryParam("context") Optional<String> context, final User user )
{
//
log.debug("esIndexName: " + esIndexName);
Expand All @@ -188,7 +196,7 @@ public Any updateUsername(@ApiParam(hidden=true)final ServerRequest serverReques
log.debug("file: " + user);


return Any.wrap(user);
return response().entity(Any.wrap(user)).build();

}

Expand Down
31 changes: 29 additions & 2 deletions src/main/java/com/wurrly/modules/ConfigModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import com.google.inject.util.Types;
import com.jsoniter.DecodingMode;
import com.jsoniter.JsonIterator;
import com.jsoniter.annotation.JsoniterAnnotationSupport;
import com.jsoniter.output.EncodingMode;
import com.jsoniter.output.JsonStream;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigObject;
Expand All @@ -37,7 +42,7 @@ public class ConfigModule extends AbstractModule
*/

protected String configFile = "application.conf";
protected Config config = null;

public ConfigModule()
{
Expand All @@ -59,6 +64,25 @@ protected void configure()
this.bindConfig(fileConfig(configFile));
}

JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_WITH_HASH);
JsonStream.setMode(EncodingMode.DYNAMIC_MODE);
JsoniterAnnotationSupport.enable();

install(new RoutingModule(this.config));



// try
// {
// Class<? extends DefaultResponseListener> defaultResponseListener = (Class<? extends DefaultResponseListener>) Class.forName(config.getString("application.defaultResponseListener"));
//
// this.bind(DefaultResponseListener.class).to(defaultResponseListener).in(Singleton.class);
//
// } catch (Exception e)
// {
// log.error(e.getMessage(),e);
// }

}


Expand Down Expand Up @@ -93,7 +117,10 @@ public void bindConfig(final Config config)
}
}
// bind config
this.binder().bind(Config.class).toInstance( ConfigFactory.load(config) );

this.config = ConfigFactory.load(config);

this.binder().bind(Config.class).toInstance( config );

log.info("Config:\n" + config);

Expand Down
Loading

0 comments on commit a0c5cd5

Please sign in to comment.