Custom Error Page in PlayFramework2.4.x - java

I did these and still can't see my custom page, please help,
Added MyGlobal.java extends GlobalSettings
Added onHandlerNotFound to override:
#Override
public F.Promise<Result> onHandlerNotFound(RequestHeader request) {
Logger.error("onHandlerNotFound!");
return Promise.<Result> pure(Results.internalServerError(views.html.page404.render()));
}
Added application.global = "MyGlobal" in application.conf
But nothing happends, play2.4.6 still runs out the default page from devNotFound.scala.html in playframework source folder of framework/play/src/main/scala/views/defaultpages/
Please help.

The way to do it in Play 2.4.x is to use an HttpErrorHandler as documented here:
https://www.playframework.com/documentation/2.4.x/JavaErrorHandling
You can just extends the DefaultHttpErrorHandler and add return your custom pages:
https://www.playframework.com/documentation/2.4.x/JavaErrorHandling#Extending-the-default-error-handler
https://www.playframework.com/documentation/2.4.x/api/java/play/http/DefaultHttpErrorHandler.html
Here is a full example, considering that you are trying to override the default 404 page:
package com.acme.controllers.handlers;
import play.*;
import play.api.OptionalSourceMapper;
import play.api.UsefulException;
import play.api.routing.Router;
import play.http.DefaultHttpErrorHandler;
import play.libs.F.*;
import play.mvc.Http.*;
import play.mvc.*;
import javax.inject.*;
public class ErrorHandler extends DefaultHttpErrorHandler {
#Inject
public ErrorHandler(Configuration configuration, Environment environment,
OptionalSourceMapper sourceMapper, Provider<Router> routes) {
super(configuration, environment, sourceMapper, routes);
}
#Override
protected Promise<Result> onNotFound(RequestHeader request, java.lang.String message) {
Logger.error("onHandlerNotFound!");
return Promise.pure(Results.internalServerError(views.html.page404.render()));
}
}
And then, you need to configure in your conf/application.conf like this:
play.http.errorHandler = "com.acme.controllers.handlers.ErrorHandler"

public class Global extends GlobalSettings {
#Override
public Promise<SimpleResult> onHandlerNotFound(RequestHeader request) {
return Promise.<SimpleResult>pure(internalServerError(views.html.page404.render()));
}
}

#Override
protected F.Promise<Result> onNotFound(RequestHeader request, String message) {
Logger.debug("onNotFound: " + message);
return Promise.<Result> pure(Results
.ok(views.html.admin.page404.render(request.method(), request.uri())));
}
Thanks for help, it really does work in dev env..
I already had the MyErrorHandler.java but not overriding the onNotFound function, because i was almost lost in the extending GlobalSettings's onHandlerNotFound.

Related

Import greyed out in Java

I've just started using Java today and have created some tests but I want to use JavascriptExecutor to be able to report tests passing or failing to Sauce Labs. I've imported the library I believe I need but it doesn't recognise the import either way. I believe I am doing it correctly but evidently I'm not and would like some help to understand where I'm going wrong.
My code looks like this:
package tests;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import pageobjects.Login;
import org.junit.jupiter.api.extension.TestWatcher;
import org.openqa.selenium.JavascriptExecutor;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class TestLogin extends BaseTest {
private Login login;
#RegisterExtension
public SauceTestWatcher watcher = new SauceTestWatcher();
#Before
public void setUp() {
login = new Login(driver);
}
#Test
public void succeeded() {
login.with("tomsmith", "SuperSecretPassword!");
assertTrue("success message not present",
login.successMessagePresent());
}
#Test
public void failed() {
login.with("tomsmith", "bad password");
assertTrue("failure message wasn't present after providing bogus credentials",
login.failureMessagePresent());
}
#Test
public void failed2() {
login.with("tomsmith", "bad password");
assertFalse("success message was present after providing bogus credentials",
login.successMessagePresent());
}
public class SauceTestWatcher implements TestWatcher {
#Override
public void testSuccessful(ExtensionContext context) {
driver.executeScript("sauce:job-result=passed");
driver.quit();
}
#Override
public void testFailed(ExtensionContext context, Throwable cause) {
driver.executeScript("sauce:job-result=failed");
driver.quit();
}
}
}
I use import org.openqa.selenium.JavascriptExecutor; to get and I'm referencing it at the bottom: driver.executeScript("sauce:job-result=failed"); or the passed just above it.
Invalidating cache and restarting resolved. Also changed the code slightly.
((JavascriptExecutor) driver).executeScript("sauce:job-result=passed");
This resolved my issue

Spring Boot + Liquibase - custom LockService class

I'm trying to mplement custom LockService class like it said in this answer: https://stackoverflow.com/a/15567073/5182320
package liquibase.ext;
import liquibase.exception.DatabaseException;
import liquibase.lockservice.StandardLockService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
#Slf4j
#Configuration
public class TimeoutLockService extends StandardLockService {
#SneakyThrows
#Override
public void waitForLock() {
forceReleaseLock();
}
#Override
public int getPriority() {
return super.getPriority() + 1;
}
#Override
public void init() throws DatabaseException {
super.init();
log.info("Init called");
}
}
Placed the class in the package liquibase.ext
But when I'm running my application it's ignoring this class and still trying to acquire the lock.
I was trying to do something similar and I had a similar issue, where my changes were not pickup, even though it was in package liquibase.ext . I am using liquibase 4.3.5 and the following document helped me.
Starting with 4.0, we switched to the standard java.util.ServiceLoader system to find extension classes.
https://docs.liquibase.com/tools-integrations/extensions/extension-upgrade-guides/lb-4.0-upgrade-guide.html
I had to crate the liquibase.lockservice.LockService file in META-INF/services with my implementation and solve the issue.

Proxy for abstract class without changing the usage

I have an abstract class (database mapping) implementing an interface where default implementations are injected at runtime (this is part of another library and cannot be changed).
I want to override one of the default implementation via a proxy (as that seems like the way to override this).
public abstract class Table1 implements Storable<Table1>
{
#Sequence("ID_SEQUENCE")
#Alias("ID")
public abstract String getID();
public abstract void setID(String ID);
#Alias("NAME")
public abstract String getAvailabilityZone();
public abstract void setAvailabilityZone(String value);
}
public interface Storable<S extends Storable<S>> {
//a bunch of method definition.
boolean tryLoad() throws Exception;
}
Let's say I want to override tryLoad() method to do my own things instead of what the generated code provides. Given the nature of the library, it is not something I can achieve by simple #Override.
The simple way this is currently used is as following:
public void method() {
Table1 t = Repository.storageFor(Table1.class).prepare();
t.setName( "temp" );
if (!t.tryLoad())
t.tryInsert();
}
I want to proxy tryLoad() without making changes in all the methods across the whole codebase - that would be to get proxied instance instead of actual one and perform the operation on that.
Is there any recommended way to achieve this?
Thanks!
I woke up last night and felt bored, so despite your lack of feedback I created a little Carbonado showcase project and shared it on GitHub. I made three commits:
Initial commit with Maven project already prepared for AspectJ and a JUnit test for me to find out how Carbonado actually works, because I had never used it before.
Add failing unit test for behaviour of tryLoad() expected to be provided by aspect.
Add aspect to make unit test pass. Aspect hooks into tryLoad() and auto-creates non-existent record. I do not know if I guessed right what you actually wanted to achieve, but if it was a different thing, just change the aspect implementation.
Sample code
Carbonado storable:
package de.scrum_master.app;
import com.amazon.carbonado.Nullable;
import com.amazon.carbonado.PrimaryKey;
import com.amazon.carbonado.Storable;
#PrimaryKey("ID")
public interface StoredMessage extends Storable<StoredMessage> {
long getID();
void setID(long id);
#Nullable String getMessage();
void setMessage(String message);
}
Aspect:
package de.scrum_master.aspect;
import com.amazon.carbonado.Storable;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class CarbonadoAspect {
#Around("call(boolean tryLoad()) && target(storable)")
public boolean tryInsertIfNotFound(ProceedingJoinPoint thisJoinPoint, Storable storable) throws Throwable {
System.out.println(thisJoinPoint);
if ((boolean) thisJoinPoint.proceed())
return true;
System.out.println("Not found: " + storable + " -> inserting");
return storable.tryInsert();
}
}
JUnit test:
package de.scrum_master.app;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.amazon.carbonado.FetchException;
import com.amazon.carbonado.PersistException;
import com.amazon.carbonado.Repository;
import com.amazon.carbonado.RepositoryException;
import com.amazon.carbonado.Storage;
import com.amazon.carbonado.SupportException;
import com.amazon.carbonado.repo.map.MapRepositoryBuilder;
import de.scrum_master.app.StoredMessage;
public class CarbonadoTest {
private Repository repo;
private Storage<StoredMessage> storage;
StoredMessage message;
#Before
public void setUp() throws Exception {
repo = MapRepositoryBuilder.newRepository();
storage = repo.storageFor(StoredMessage.class);
message = storage.prepare();
}
#After
public void tearDown() throws Exception {
repo.close();
repo = null;
storage = null;
message = null;
}
// (...)
#Test
public void aspectCreatesNonExistentRecord() throws SupportException, RepositoryException {
message.setID(1);
// Without the aspect this would be false
assertTrue(message.tryLoad());
assertEquals(message.getID(), 1);
assertEquals(message.getMessage(), null);
}
}
Enjoy!

How to write Unit Test for this class using Jersey 2 test framework

I am trying to write unit test for a Rest api call which is having a POST method for adding a video file to web based application using Jersey2. Here is the signature of the method of my class(TemplateController.java) for which I want to write unit test:
#POST
#Path("/video/add")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response addVideoData(
#Context HttpServletRequest request,
AttachmentDTO attachmentDTO) {
...
}
Here is my test method of the test class (TemplateControllerUnitTestCase.java):
#Test
public void videoAdd_requestObjectIsNull_ResponseStatusIsOK() throws Exception {
// arrange
Builder builder = target("/target/video/add").request();
// action
final Response response = builder.post(Entity.entity(attachemntDTO, MediaType.APPLICATION_JSON));
// assertion
...
}
I'm able to pass the AttachmentDAO object to the TemplateController class from test class but unable to pass the request object which is becoming null in the method(addVideoData()) of the TemplateController.java class.
I'm using RequestHelper class which is a helper class for HttpServletRequest, so I want to pass an object of this class to the method(addVideoData()) using Jersey2 test framework.
You can use the HK2 capabilities of Jersey 2, that helps with Dependency Injection. Doing it this way, you can create a Factory for HttpServletRequest and return the mock from your RequestHelper. For example
public class HttpServletRequestFactory implements Factory<HttpServlet> {
#Override
public HttpServletRequest provide() {
return RequestHelper.getMockServletRequest();
}
#Override
public void dispose(HttpSession t) {
}
}
Then in your JerseyTest subclass, just register an AbstractBinder with the ResourceConfig. For example
#Override
public Application configure() {
ResourceConfig config = new ResourceConfig(...);
config.register(new AbstractBinder(){
#Override
public void configure() {
bindFactory(HttpServletRequestFactory.class).to(HttpServletRequest.class);
}
});
}
Another option
...is to not mock the HttpServletRequest at all, and use the actual HttpServletRequest. To do that, we need to configure the DeploymentContext as we override the getDeploymentContext(), and return a ServletDeploymentContext. You can see an example here and here. The first has also has an example of using a Factory, while the second show an example of how to configure based on web.xml settings. If you chose the case for mocking the HttpServletRequest, then you wouldn't need to override the getTestContainerFactory and configureDeployment as seen in the examples. Simply using the Application configure() override is enough, as long as nothing else is dependent on servlet features.
The examples in the link use
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey.version}</version>
</dependency>
Extra
Both the example I linked to are trying to take advantage of the Sevlet features. So I'll give a complete example of using a request mock.
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Assert;
import org.junit.Test;
public class MockHttpSevletRequestTest extends JerseyTest {
#Path("http")
public static class HttpResource {
#GET
public Response getResponse(#Context HttpServletRequest request) {
return Response.ok(request.getMethod()).build();
}
}
#Override
public Application configure() {
ResourceConfig config = new ResourceConfig(HttpResource.class);
config.register(new AbstractBinder() {
#Override
public void configure() {
bindFactory(HttpServletRequestFactory.class)
.to(HttpServletRequest.class);
}
});
return config;
}
public static class HttpServletRequestFactory implements Factory<HttpServletRequest> {
#Override
public HttpServletRequest provide() {
return new MockHttpServletRequest();
}
#Override
public void dispose(HttpServletRequest t) {
}
}
#Test
public void test() {
String response = target("http").request().get(String.class);
System.out.println(response);
Assert.assertEquals("POST", response);
}
}
MockHttpServletRequest is simple a dummy implementation of HttpServletRequest where I only override one method getMethod() and always return POST. You can see from the result, that even though it's a get request, it still returns POST
public class MockHttpServletRequest implements HttpServletRequest {
#Override
public String getMethod() {
return "POST";
}
...
}

Amdatu: How to make ExceptionMapper (#Provider) to work?

I'm trying to manage all my exceptions with an ExceptionMapper, as i saw in multiple documentation and examples. However, it doesn't seem to work, at least in my conditions.
I'm in a OSGI environment, using the Felix Witheboard pattern, with Amdatu Wink, so i don't have a web.xml and everything is supposed to be managed by itself.
I tried to register my ExceptionMapper as a service as i did with my web services, with no results.
#Component(immediate=true, provide={Object.class})
#Provider
public class SessionTimeoutExeptionHandler implements ExceptionMapper<SessionTimeoutException>{
public Response toResponse(SessionTimeoutException arg0) {
Response toReturn = Response.status(Status.FORBIDDEN)
.entity("session_timeout")
.build();
return toReturn;
};
}
Don't pay attention to the Response itself, i was just playing around.
My code is never called, how am i supposed to setup that provider?
You have to register the Provider in a javax.ws.rs.core.Application. That Application should be registered as a service with a higher service ranking than the default one created by the Amdatu Wink bundle.
The following is a working example.
The Exception Mapper itself:
#Provider
public class SecurityExceptionMapper implements ExceptionMapper<SecurityException>{
#Override
public Response toResponse(SecurityException arg0) {
return Response.status(403).build();
}
}
The Application:
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
public class MyApplication extends Application {
#Override
public Set<Object> getSingletons() {
Set<Object> s = new HashSet<Object>();
s.add(new JacksonJsonProvider());
s.add(new SecurityExceptionMapper());
return s;
}
}
Activator setting the service ranking property.
public class Activator extends DependencyActivatorBase{
#Override
public void destroy(BundleContext arg0, DependencyManager arg1) throws Exception {
}
#Override
public void init(BundleContext arg0, DependencyManager dm) throws Exception {
Properties props = new Properties();
props.put(Constants.SERVICE_RANKING, 100);
dm.add(createComponent().setInterface(Application.class.getName(), props).setImplementation(MyApplication.class));
}
}

Categories