Compatibility of ContainerResponseFilter in jersey 1.17 - filter

Can i run my CustomFilter extended with ContainerResponseFilter in jersey1.17.
I am using GrizzlyWebServer. Please suggest . Given below is my sample server code to add the filter.
GrizzlyWebServer webServer = new GrizzlyWebServer(.............);
....
....
ServletAdapter adapter3 = new ServletAdapter();
adapter3.addInitParameter("com.sun.jersey.config.property.packages", "com.motilink.server.services");
adapter3.setContextPath("/");
adapter3.setServletInstance(new ServletContainer());
adapter3.addContextParameter(ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS, PoweredbyResponseFilter.class.getName());
webServer.addGrizzlyAdapter(adapter3, new String[]{"/"});
...
.....

MY Filter:
#FrontierResponse
#Provider
public class PoweredbyResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
System.out.println("hell");
responseContext.getHeaders().add("X-Powered-By", "Jersey :-)");
}
}
Resource Class:
#NameBinding
#Retention(value = RetentionPolicy.RUNTIME)
public #interface FrontierResponse {
}
#GET
#Produces("text/plain")
#Path("plain")
//#FrontierResponse
public String getMessage() {
System.out.println("hello world called");
return "Hello World";
}
and finally i call it from a browser
http:// localhost:4464/plain

Add the ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS property as a init-param and not as a context-param:
...
adapter3.addInitParameter(ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS, PoweredbyResponseFilter.class.getName());
...
EDIT 1
From your answer it seems that you're actually trying to use Jersey 1.x (1.17) runtime with implemented JAX-RS 2.0 providers (ContainerRequestContext and ContainerResponseContext have been introduced in JAX-RS 2.0 and Jersey 1.x doesn't know how to use them).
So my advice would be - drop all your Jersey 1.17 dependencies and replace them with Jersey 2.x dependencies. Take a look at our helloworld-webapp example (particularly at App class) to see how to create a Grizzly server instance with JAX-RS application.
Note that it is sufficient to add just ServerProperties.PROVIDER_PACKAGES property to init-params and your Resources and Providers (incl. response filters) will be scanned and registered in the application.

Related

Olingo with Spring Boot

I am using this tutorial and it works for a simple java web application. Now I want to convert it to Spring Boot. I remove the web.xml and add the following two annotations to DemoServlet
#RestController
public class DemoServlet extends DispatcherServlet {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(DemoServlet.class);
#RequestMapping("/DemoService.svc/*")
protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
try {
// create odata handler and configure it with CsdlEdmProvider and Processor
OData odata = OData.newInstance();
ServiceMetadata edm = odata.createServiceMetadata(new DemoEdmProvider(), new ArrayList<EdmxReference>());
ODataHttpHandler handler = odata.createHandler(edm);
handler.register(new DemoEntityCollectionProcessor());
// let the handler do the work
handler.process(req, resp);
} catch (RuntimeException e) {
LOG.error("Server Error occurred in ExampleServlet", e);
throw new ServletException(e);
}
}
}
I also change the HTTPServlet to DispatcherServlet.
Now I am only able to access one end point. i.e.
http://localhost:8080/DemoService.svc/
The metadata end point is not working. It returns the service document instead of xml content.
http://localhost:8080/DemoService.svc/$metadata
Can somebody explain what is going on here?
user the below code for the process method.
handler.process(new HttpServletRequestWrapper(request) {
// Spring MVC matches the whole path as the servlet path
// Olingo wants just the prefix, ie upto /odata, so that it
// can parse the rest of it as an OData path. So we need to override
// getServletPath()
#Override
public String getServletPath() {
return "/DemoService.svc";
}
}, response);
You can create a #Configuration and Map your servlet in it like the following
#Bean
public ServletRegistrationBean odataServlet() {
ServletRegistrationBean odataServRegstration = new ServletRegistrationBean(new CXFNonSpringJaxrsServlet(),
"/DemoService.svc/*");
Map<String, String> initParameters = new HashMap<>();
initParameters.put("javax.ws.rs.Application", "org.apache.olingo.odata2.core.rest.app.ODataApplication");
initParameters.put("org.apache.olingo.odata2.service.factory",
"com.metalop.code.samples.olingo.springbootolingo2sampleproject.utils.JPAServiceFactory");
odataServRegstration.setInitParameters(initParameters);
return odataServRegstration;
}
Add the following after the handler.register call:
req.setAttribute("requestMapping", "/DemoService.svc");
The best implementation of olingo2 and spring-boot can be found here. I would suggest to take a look at this repository, it is very straight forward and easy.

404 on Properly mapped SpringBoot RestController

I'm experiencing a little issue that is wasting a lot of my time...
I've created, for demonstration purposes, a simple SpringBoot application using the Eclipse New > Spring Starter Project.
Here is my Application class:
package it.asirchia;
//All needed imports
#SpringBootApplication
public class Application {
public static HashMap<Long,Book> books = new HashMap<Long, Book>();
public static HashMap<Long,Editor> editors = new HashMap<Long, Editor>();
public static HashMap<Long,Person> authors = new HashMap<Long, Person>();
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Then I've created the EditorsApis Controller:
package it.asirchia.apis;
//All needed imports
#RestController
#RequestMapping(value="/editors")
public class EditorsApis {
private static long counter = 0;
#RequestMapping(value="/", method=RequestMethod.GET)
public HashMap<Long, Editor> getAllEditor(){
return Application.editors;
}
#RequestMapping(value="/", method=RequestMethod.POST)
public void postNewEditor(#RequestBody Editor editor){
Application.editors.put(counter++, editor);
}
#RequestMapping(value="/{editorid}", method=RequestMethod.PUT)
public void updateEditor(#PathVariable long editorid,
#RequestBody Editor editor){
Application.editors.put(editorid, editor);
}
#RequestMapping(value="/{editorid}", method=RequestMethod.GET)
public Editor getEditor(#PathVariable long editorid){
return Application.editors.get(editorid);
}
#RequestMapping(value="/{editorid}", method=RequestMethod.DELETE)
public void deleteEditor(#PathVariable long editorid){
Application.editors.remove(editorid);
}
}
And an AuthorsApis and a BooksApis controllers that are very similar to the EditorApis one.
Of course I've created too all the three Pojos:
Editor.class, Person.class and Book.class
I've started up the Eclipse embedded Spring runtime and I can see that all the paths are properly mapped:
INFO [main] s.w.s.m.m.a.RequestMappingHandlerMapping Mapped "
{[/authors/],methods=[GET]}" onto public java.util.HashMap it.asirchia.apis.AuthorsApis.getAllAuthors()
And so on and so forth for all the other Rest APIs I've implemented.
The last three lines of the log are:
Starting beans in phase 0
Tomcat started on port(s): 8080 (http)
Started Application in 5.547 seconds (JVM running for 6.169)
Ok, for me wverything is properly configured, up and running. But when I try to invoke
GET /authors HTTP/1.1
Host: localhost:8080
I obtain:
{
"timestamp": 1507286437765,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/authors"
}
And the same happens for ALL the REST APIs I've implemented.
Any idea about the reason of this problem?
Thank you.
The following mapping will work localhost:8080/authors/ for you.Since in your method mapping GET you have added the "/" so you should provide the trailing slash in URL also. If you want mapping like this localhost:8080/authors then follow the below code,
#RequestMapping(value={"","/"}, method=RequestMethod.GET)
public HashMap<Long, Editor> getAllEditor(){
return Application.editors;
}
The above will accept,
1) localhost:8080/editors
2) localhost:8080/editors/
Hope this will help.
Can you just try to add a action content in value.Here only specifying only a "/".Like
#RequestMapping(value="/updateEditor", method=RequestMethod.GET)
If you need to add any path variable,you can modify the same with following,
#RequestMapping(value="/updateEditor/{editorid}", method=RequestMethod.PUT)
Just try this method also.

Custom JASPIC on WebSphere error message

Though similar, the specific problem I have is not addressed in Use JASPIC auth module on WebSphere 8.5
I am getting the following error message:
SECJ8027E: The path and name of file where JASPI persistent registrations are stored must be specified using property com.ibm.websphere.jaspi.configuration.
I can set the custom property in the administration to some existing folder but I wanted to make sure that is the right approach or if there is some step I was missing.
Note I am specifically using the "embedded in application" approach rather than a server installed JASPIC module so I have something like this
#WebListener
public class JaspicInitializer implements
ServletContextListener {
#Override
public void contextInitialized(final ServletContextEvent sce) {
final Map<String, String> options = new HashMap<>();
AuthConfigFactory.getFactory()
.registerConfigProvider(AuthModuleConfigProvider.class.getName(), options, "HttpServlet", null, null);
}
}
I had the error on both WebSphere 8.5.5.11 and 9.0.0.3
From #Uux comment, I changed the way I do the registration so it no longer give the error.
#WebListener
public class JaspicInitializer implements
ServletContextListener {
private String registrationID;
#Override
public void contextDestroyed(final ServletContextEvent sce) {
AuthConfigFactory.getFactory().removeRegistration(registrationID);
}
#Override
public void contextInitialized(final ServletContextEvent sce) {
final ServletContext context = sce.getServletContext();
registrationID = AuthConfigFactory.getFactory()
.registerConfigProvider(new AuthModuleConfigProvider(), "HttpServlet",
context.getVirtualServerName() + " " + context.getContextPath(), "JEE Sample");
}
}
Also WebSphere Global Security needs to be configured with
Enable application security
Enable Java Authentication SPI (JASPI)

how to change the #FeignClient name in runtime

I use Spring Cloud Netflix to build my micro service .
#FeignClient(name = "ms-cloud",configuration = MsCloudClientConfig.class)
public interface TestClient {
/**
* #return
*/
#RequestMapping(value = "/test", method = RequestMethod.GET)
String test();
}
I want to change the name to ms-cloud-pre when some special user.
Anyone can give some advice?
According to the documentation feign supports placeholders in the name and url fields.
#FeignClient(name = "${store.name}")
public interface StoreClient {
//..
}
So you could set store.name=storeProd at runtime using normal spring boot configuration mechanisms.
To create a spring-cloud Feign client at runtime in situations where you don't know the service-id until the point of call:
import org.springframework.cloud.openfeign.FeignClientBuilder;
#Component
public class InfoFeignClient {
interface InfoCallSpec {
#RequestMapping(value = "/actuator/info", method = GET)
String info();
}
FeignClientBuilder feignClientBuilder;
public InfoFeignClient(#Autowired ApplicationContext appContext) {
this.feignClientBuilder = new FeignClientBuilder(appContext);
}
public String getInfo(String serviceId) {
InfoCallSpec spec =
this.feignClientBuilder.forType(InfoCallSpec.class, serviceId).build();
return spec.info();
}
}
That actually is possible. In Spring Cloud Zookeeper we're doing a similar thing since the name of the service in the Feign client is not the one that is there in the in Zookeeper. It can be an alias presented in the yaml file. Here you have the code example https://github.com/spring-cloud/spring-cloud-zookeeper/blob/master/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/dependency/DependencyRibbonAutoConfiguration.java#L54 and here you have the description of the dependencies feature - https://github.com/spring-cloud/spring-cloud-zookeeper/blob/master/docs/src/main/asciidoc/spring-cloud-zookeeper.adoc#using-the-zookeeper-dependencies

How to use jersey 2.0 guice on grizzly

I want to use Guice + Jersey 2.0 on Grizzly. According to this How to use guice-servlet with Jersey 2.0? discussion there is no direct Guice integration for Jersey2 at present but it can be achieved using HK2 as a bridge. I also checked the sample project in Github https://github.com/piersy/jersey2-guice-example-with-test . This project is implemented using Jetty.
But my problem is to implement it in Grizzly. On Jetty it is used like this
#Inject
public MyApplication(ServiceLocator serviceLocator) {
// Set package to look for resources in
packages("example.jersey");
System.out.println("Registering injectables...");
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(Main.injector);
}
My problem on grizzly is , how to get this serviceLocator object?
Thank you.
I have created the sample here
https://github.com/oleksiys/samples/tree/master/jersey2-guice-example-with-test
The Grizzly initialization code looks like this:
final URI uri = UriBuilder.fromUri("http://127.0.0.1/")
.port(8080).build();
// Create HttpServer
final HttpServer serverLocal = GrizzlyHttpServerFactory.createHttpServer(uri, false);
// Create Web application context
final WebappContext context = new WebappContext("Guice Webapp sample", "");
context.addListener(example.jersey.Main.class);
// Initialize and register Jersey ServletContainer
final ServletRegistration servletRegistration =
context.addServlet("ServletContainer", ServletContainer.class);
servletRegistration.addMapping("/*");
servletRegistration.setInitParameter("javax.ws.rs.Application",
"example.jersey.MyApplication");
// Initialize and register GuiceFilter
final FilterRegistration registration =
context.addFilter("GuiceFilter", GuiceFilter.class);
registration.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), "/*");
context.deploy(serverLocal);
serverLocal.start();
add dependecy
compile group: "org.glassfish.hk2", name: "guice-bridge", version: "2.4.0"
create feature
public class GuiceFeature implements Feature {
#Override
public boolean configure(FeatureContext context) {
ServiceLocator serviceLocator = ServiceLocatorProvider.getServiceLocator(context);
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(YYY.class).to(ZZZ.class);
}
});
guiceBridge.bridgeGuiceInjector(injector);
return true;
}
}
register feature
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(GuiceFeature.class);

Resources