I've been using the onStart method for a while and it works no problem, but when I try to override onBadRequest, I get an error:
Here's the class:
import models.User;
import play.Application;
import play.GlobalSettings;
import play.Logger;
import play.mvc.Result;
import views.html.error_page;
import static play.mvc.Results.badRequest;
public class Global extends GlobalSettings {
#Override
public void onStart(Application app){
Logger.info("Application started!");
// Check if the database is empty
if(User.find.findRowCount()==0){
Ebean.save((List) Yaml.load("initial-data.yml"));
}
}
#Override
public void onStop(Application app){
Logger.info("Application stopped!");
}
#Override
public Result onBadRequest(String uri, String error) {
Logger.info("Bad Request");
return badRequest(error_page.render());
}
}
The first two work no problem, but the third one causes the error.
Here's the API entry:
You used the old API.
Here's the API for Play 2.1.1:
http://www.playframework.com/documentation/api/2.1.1/java/play/GlobalSettings.html
Called when an action has been found, but the request parsing has failed.
Result onBadRequest(Http.RequestHeader request, java.lang.String error)
Called when an exception occurred.
Result onError(Http.RequestHeader request, java.lang.Throwable t)
This works:
#Override
public Result onError(Http.RequestHeader request, Throwable t){
Logger.error("Error thrown: " + t.getMessage());
return internalServerError(error_page.render());
}
This page was useful. I'm still confused why the API is wrong.
I hope this helps out somebody with a similar problem.
Related
My project is working on getting data from one system to another. We are using Apache Camel Routes to send the data between JBoss EAP v7 servers. My question is, is there a way to investigate what the content of the packages are as they come across different routes?
We have tried upping the logging but our files/console just get flooded. We have also tried to use Hawtio on the server to see the messages coming across the routes but have had no success identifying where our message is getting "stuck".
Any help is appreciated!
You can use unit tests to test your routes locally and then either log contents of the exchange at specific points using adviceWith and weave methods.
With unit tests you can easily debug your routes in your favourite IDE even if you're running camel in something like Karaf or Red Hat fuse.
package com.example;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.model.dataformat.JsonLibrary;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class ExampleRouteTests extends CamelTestSupport {
#Test
public void exampleTest() throws Exception
{
ContractDetails testDetails = new ContractDetails(1512, 1215);
mockJDBCEndpoints();
context.getRouteDefinition("exampleRoute")
.adviceWith(context, new AdviceWithRouteBuilder(){
#Override
public void configure() throws Exception {
replaceFromWith("direct:start");
weaveByToUri("direct:getDetailsFromAPI")
.replace()
.to("log:testLogger?showAll=true")
.to("mock:api")
.setBody(constant(testDetails));
weaveByToUri("direct:saveToDatabase")
.replace()
.to("log:testLogger?showAll=true")
.to("mock:db");
}
});
MockEndpoint apiMockEndpoint = getMockEndpoint("mock:api");
apiMockEndpoint.expectedMessageCount(1);
MockEndpoint dbMockEndpoint = getMockEndpoint("mock:db");
dbMockEndpoint.expectedMessageCount(1);
context.start();
String body = "{\"name\":\"Bob\",\"age\":10}";
template.sendBody("direct:start", body);
apiMockEndpoint.assertIsSatisfied();
dbMockEndpoint.assertIsSatisfied();
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder(){
#Override
public void configure() throws Exception {
from("amqp:queue:example")
.routeId("exampleRoute")
.unmarshal().json(JsonLibrary.Jackson,
Person.class)
.to("direct:getDetailsFromAPI")
.process(new SomeProcessor())
.to("direct:saveToDatabase");
from("direct:saveToDatabase")
.routeId("saveToDatabaseRoute")
.to("velocity:sql/insertQueryTemplate.vt")
.to("jdbc:exampleDatabase");
from("direct:getDetailsFromAPI")
.removeHeaders("*")
.toD("http4:someAPI?name=${body.getName()}")
.unmarshal().json(JsonLibrary.Jackson,
ContractDetails.class);
}
};
}
void mockJDBCEndpoints() throws Exception {
context.getRouteDefinition("saveToDatabaseRoute")
.adviceWith(context, new AdviceWithRouteBuilder(){
#Override
public void configure() throws Exception {
weaveByToUri("jdbc:*")
.replace()
.to("mock:db");
}
});
}
#Override
public boolean isUseAdviceWith() {
return true;
}
}
Now for troubleshooting problems that do not occur with unit tests you can configure generic or route specific exception handling with onException and use Dead letter channel to process and and store information about the failed exchange. Alternatively you can just use stream or file component to save information about the exception and failed exchange in to a separate file to avoid flooding logs.
I'm facing an issue in Play framework (2.6) while trying to handle an exception using the HttpErrorHandler mechanism in a specific scenario.
I have a simple ErrorHandler in the root package:
import play.Logger;
import play.http.HttpErrorHandler;
import play.mvc.Http;
import play.mvc.Result;
import play.mvc.Results;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
public class ErrorHandler implements HttpErrorHandler {
#Override
public CompletionStage<Result> onClientError(Http.RequestHeader request, int statusCode, String message) {
Logger.error("client error");
return CompletableFuture.completedFuture(Results.status(statusCode, "A client error occurred: " + message));
}
#Override
public CompletionStage<Result> onServerError(Http.RequestHeader request, Throwable exception) {
Logger.error("server error");
return CompletableFuture.completedFuture(
Results.internalServerError("A server error occurred: " + exception.getMessage()));
}
}
I created a custom controller to handle the assets:
package controllers;
import org.apache.commons.lang3.StringUtils;
import play.api.mvc.Action;
import play.api.mvc.AnyContent;
import play.mvc.Controller;
import javax.inject.Inject;
public class AssetsCustomController extends Controller {
private final Assets assets;
#Inject
public AssetsCustomController(Assets assets) {
this.assets = assets;
}
public Action<AnyContent> at(String path, String file) {
if (StringUtils.isEmpty(path)) {
throw new IllegalArgumentException();
}
return assets.at(path, file, false);
}
}
I've checked the ErrorHandler and is working fine for all the cases except when the exception is thrown from this method in AssetsCustomController:
public Action<AnyContent> at(String path, String file) {
if (StringUtils.isEmpty(path)) {
throw new IllegalArgumentException();
}
return assets.at(path, file, false);
}
For instance, when the IllegalArgumentException is thrown, my ErrorHandler is ignored and Play uses his native error handler. Here is the stacktrace:
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[IllegalArgumentException: null]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:255)
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:182)
at play.api.http.DefaultHttpErrorHandler$.onServerError(HttpErrorHandler.scala:286)
at play.core.server.Server.logExceptionAndGetResult$1(Server.scala:53)
at play.core.server.Server.getHandlerFor(Server.scala:83)
at play.core.server.Server.getHandlerFor$(Server.scala:49)
at play.core.server.AkkaHttpServer.getHandlerFor(AkkaHttpServer.scala:42)
at play.core.server.AkkaHttpServer.getHandler(AkkaHttpServer.scala:215)
at play.core.server.AkkaHttpServer.handleRequest(AkkaHttpServer.scala:195)
at play.core.server.AkkaHttpServer.$anonfun$createServerBinding$3(AkkaHttpServer.scala:107)
Caused by: java.lang.IllegalArgumentException: null
at controllers.AssetsCustomController.at(AssetsCustomController.java:20)
at router.Routes$$anonfun$routes$1.$anonfun$applyOrElse$10(Routes.scala:183)
at play.core.routing.HandlerInvokerFactory$$anon$6$$anon$7.call(HandlerInvoker.scala:61)
at play.core.routing.GeneratedRouter$$anon$2.call(GeneratedRouter.scala:251)
at router.Routes$$anonfun$routes$1.$anonfun$applyOrElse$9(Routes.scala:183)
at play.core.routing.GeneratedRouter.$anonfun$call$5(GeneratedRouter.scala:99)
at scala.util.Either.fold(Either.scala:118)
at play.core.routing.GeneratedRouter.call(GeneratedRouter.scala:99)
at router.Routes$$anonfun$routes$1.applyOrElse(Routes.scala:182)
at router.Routes$$anonfun$routes$1.applyOrElse(Routes.scala:154)
[SOLUTION]
Thanks to the answer Flo354, I was able to solve the problem and the AssetsCustomController is like this:
package controllers;
import akka.stream.Materializer;
import org.springframework.util.StringUtils;
import play.mvc.Controller;
import play.mvc.Result;
import javax.inject.Inject;
import java.util.concurrent.CompletionStage;
public class AssetsCustomController extends Controller {
private final Assets assets;
private final Materializer materializer;
#Inject
public AssetsCustomController(Materializer materializer, Assets assets) {
this.materializer = materializer;
this.assets = assets;
}
public CompletionStage<Result> at(String path, String file) {
if (StringUtils.isEmpty(path)) {
throw new IllegalArgumentException();
}
return assets.at(path, file, false).asJava().apply(request()).run(materializer);
}
}
Your Action<AnyContent> is part of the Scala API, which means it does not use the Java part.
Your Custom error handler apply only to Java sources. Look at your stack trace
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[IllegalArgumentException: null]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:255)
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:182)
at play.api.http.DefaultHttpErrorHandler$.onServerError(HttpErrorHandler.scala:286)
....
You can see that it's scala when there is play.api.something
You can workaround this by sending back a CompletionStage<Result>
public CompletionStage<Result> test(String path, String file) {
if (StringUtils.isEmpty(path)) {
throw new IllegalArgumentException();
}
return assets.at(path, file, false).asJava().apply(request()).run(materializer);
}
And in your controller, don't forget to inject an instance of akka.stream.Materializer
Hope it will help!
I'm using camel 2.15.1 and I'm trying to use adviceWith() but I keep getting deprecation warnings. Below is the relevant snippet:
routeDefinition.adviceWith(camelContext, new AdviceWithRouteBuilder(){
#Override
public void configure() throws Exception {
interceptSendToEndpoint("direct:doSomething")
.skipSendToOriginalEndpoint()
}
});
I know I can avoid the deprecation warnings by casting camelContext to ModelCamelContext but casting like that has a bit of a smell to it. Is casting the right way to handle it?
https://camel.apache.org/advicewith.html
Those deprecatations has been removed in future release as we really just want people to access all what they need from CamelContext.
But it has an adapt method so you can adapt to the type without type casting
ModelCamelContext mcc = context.adapt(ModelCamelContext.class);
This solved the problem for my unit tests:
public void testMe() throws Exception{
CamelContext context = this.context();
// Get the route that we're after by ID.
RouteDefinition route = context.getRouteDefinition("<routeID>");
//override the default send endpoint.
route.adviceWith(context.adapt(ModelCamelContext.class), new RouteBuilder() {
public void configure() throws Exception {
interceptSendToEndpoint("mock:overrideme")
.skipSendToOriginalEndpoint()
.to("mock:inbound");
}
});
}
for camel version change 2 to 3, here what you can go for regarding the RouteDefination and AdviceWith , ModelCamelContext, CamelContext
`private void methodName() throws Exception {
AdviceWith.adviceWith(context, "routeId" , route -> {
route.interceptSendToEndpoint("direct:doSomething").skipSendToOriginalEndpoint();
});
context.start();
}`
The adviceWith method was moved as explained here.
AdviceWithRouteBuilder was also used in this example, which I believe is an example of this question. For now, in 2022 I think it could be better represented in the following:
package TestExamples.AdviceExamples;
import org.apache.camel.EndpointInject;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.AdviceWith;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit5.CamelTestSupport;
import org.junit.jupiter.api.Test;
/**
* Unit test demonstrating various functionality of using advice-with
*/
public class AdviceWithMockEndpointsTest extends CamelTestSupport {
#EndpointInject("mock:seda:camel")
protected MockEndpoint camelPoint;
#EndpointInject("mock:seda:other")
protected MockEndpoint otherPoint;
#Test
public void testMockEndpoints() throws Exception {
// must start Camel after we are done using advice-with
AdviceWith.adviceWith(context, "quotes", routeBuilder ->{
routeBuilder.weaveByToUri("seda:camel").replace().to(camelPoint);
routeBuilder.weaveByToUri("seda:other").replace().to(otherPoint);
});
context.start();
camelPoint.expectedBodiesReceived("Camel rocks");
otherPoint.expectedBodiesReceived("Bad donkey");
template.sendBody("seda:quotes", "Camel rocks");
template.sendBody("seda:quotes", "Bad donkey");
assertMockEndpointsSatisfied();
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("seda:quotes").routeId("quotes")
.choice()
.when(simple("${body} contains 'Camel'"))
.to("seda:camel")
.otherwise()
.to("seda:other");
}
};
}
}
I am new to GWT and trying to build a sample application. Here is my EntryPoint class.
package com.google.gwt.sample.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
public class TalkToServer implements EntryPoint {
public TalkToServer() {}
public void onModuleLoad() {
HTTPRequest.asyncGet
(GWT.getHostPageBaseURL() + "person.xml",
new ResponseTextHandler() {
public void onCompletion(String responseText) {
GWT.log("some log message");
}
});
}
}
The error here is -
log(java.lang.String,java.lang.Throwable) in com.google.gwt.core.client.GWT cannot be applied to (java.lang.String)
I have checked gwt's javadoc and found that log can take string as argument. I am not able to figure out why log is throwing this error. Please let me know if I am missing something.
Try using
GWT.log("some log message", new Throwable())
I need to make w WS call to handle HEAD request by myself, anyway it always get's response AFTER redirection (so finally I get always 200 status instead of ie. 301)
In documentation it's written that I should set ws.followRedirects=false in my application.conf, anyway it doesn't seem to work. I can see that Scala version is trying read this config, however I have a Java controller. Also can't switch to 2.1 now, where as I can see there is special setter for the issue.
Is there ANY workaround ?
You can call Scala from Java. The method wsHead encapsulates the Scala code and delivers only Objects from the Java Play API. Migrated to Play 2.1.0 you can refactor that method.
package controllers;
import play.api.libs.ws.Response;
import play.api.libs.ws.WS$;
import play.libs.F;
import play.libs.WS;
import play.mvc.*;
public class Application extends Controller {
public static Result index() {
final String url = "http://localhost:80";
final F.Promise<WS.Response> responsePromise = wsHead(url);
return async(responsePromise.map(new F.Function<WS.Response, Result>() {
#Override
public Result apply(WS.Response response) throws Throwable {
return ok("got status: " + response.getStatus());
}
}));
}
private static F.Promise<WS.Response> wsHead(String url) {
return new F.Promise(WS$.MODULE$.url(url).head()).map(new F.Function<Response, WS.Response>() {
#Override
public WS.Response apply(Response o) throws Throwable {
return new WS.Response(o.getAHCResponse());
}
});
}
}
You still need to add ws.followRedirects=false in your application.conf.