How to write global filter for mobilefirst 8.0 java adapter - ibm-mobilefirst

I need a global filter on mobilefirst 8.0 java adapter. Am tring to write ContainerRequestFilter filter. But i need some mobilefirst data in there. ConfigurationApi,AdaptersAPI. How can i get it in this context ? Or there have other way to call some code with all java adapter methods ?

You can write a ContainerRequestFilter and use it with an adapter. All you need to do is add to the getClasses() method in the adapter application class (unless it's in the same package as the application class, in this case it will happen automatically).
You can use the #Context annotation in filters to inject any MFP API you need, just like in your resource classes.
Here is a working example:
public class MyRequestFilter implements ContainerRequestFilter {
#Context
ConfigurationAPI configApi;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
doStuff();
}
}

Thanks all! Question was solved. Helped this page
https://jax-rs-spec.java.net/nonav/2.0-rev-a/apidocs/index.html about #NameBinding annotation.
and additional #Produce annotation on Filter class.

Related

Is it possible to add an instance of singleton framework to CDI context?

I'm trying to integrate StarMX framework (https://github.com/rogeriogentil/starmx) into a legacy web application. This framework uses JMX techonology and is initialized using the Singleton pattern: StarMXFramework.createInstance(). The web application uses Java EE 6 technologies such as EJB and CDI (also DeltaSpike). However, the way the framework is being initialized (code below) doesn't add its instance to the CDI context.
import org.starmx.StarMXException;
import org.starmx.StarMXFramework;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
#Startup
#Singleton
public class StarMXSingleton {
private StarMXFramework starMX;
#PostConstruct
public void postConstruct() {
try {
starMX = StarMXFramework.createInstance();
} catch (StarMXException e) {
(...)
}
}
#PreDestroy
public void preDestroy() {
if (starMX != null) {
try {
starMX.shutdown();
} catch (StarMXException e) {
(...)
}
}
}
}
I know that is possible to extend CDI, but is it possible to add an instance of singleton framework to CDI context?
There are two ways, first and easy one is a producer. Here is a link to what CDI producers are and how they work. In short, CDI will use this producer to create the instance of a bean whose types are mandated by the return type of the producer method.
The producer method has to be placed inside a CDI bean so that is it picked up by CDI. Note that the scope of the producer affects how often it will be invoked, just as it would be with standard bean. Here is how it could look like:
#ApplicationScoped
public class SomeCdiBeanInYourApplication {
#Produces //denotes producer method
#ApplicationScoped // scope of produced bean, use CDI scope (the singleton you have is EJB annotation)
public StarMXFramework produceMxFramework() {
return StarMXFramework.createInstance();
}
}
Second means is then CDI extension, namely a lifecycle observer for AfterBeanDiscovery event where you can addBean(). Here is a link to CDI 2.0 spec, feel free to browse older versions based on what version you are on.
I won't write code for that as it is rather complex and long, the producer should do the trick for you.
See also
Please explain the #Produces annotation in CDI

Swagger overrides Path-Annotations

I just got swagger to produces a valid swagger.json.
I configured swagger by using the Application-config method.
However, as soon as I override the getClasses-Method to add the swagger resouces, my JAX-RS Path-annotated classes stop working.
The method looks like this
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(io.swagger.jaxrs.listing.ApiListingResource.class);
resources.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);
return resources;
}
and invoking super.getClasses() returns am empty set.
I got too many resources in my project, which I would not like to add manually.
Is there any way swagger does not mess with my previous configuration?
Thank you!
You can use a javax.ws.rs.core.Feature. Just register the classes through the callback's FeatureContext. Annotating the feature with #Provider will have it registered through the scanning.
#Provider
public class SwaggerFeature implements Feature {
#Override
public boolean configure(FeatureContext context) {
context.register(ApiListingResource.class);
context.register(SwaggerSerializers.class);
return true;
}
}
But note that if the application is already registering the resources and providers by class-path scanning, I imagine it should also pick up the Swagger classes, as they are annotated with #Path[1] and #Provider[2]. Those are the annotations the class-path scan looks for.
I haven't tried it myself (I stopped using class-path scanning[3]), but have you tried just not registering them at all? In theory the class-path scan should pick it up.
1. io.swagger.jaxrs.listing.ApiListingResource
2. io.swagger.jaxrs.listing.SwaggerSerializers
3. When to Use JAX-RS Class-path Scanning Mechanism

How to add Custom Interceptor in Spring data rest (spring-data-rest-webmvc 2.3.0)

I am working on the spring data rest services & facing some issue in the custom interceptors. Earlier I used spring-data-rest-webmvc 2.2.0 & added interceptor in following way.
public RequestMappingHandlerMapping repositoryExporterHandlerMapping() {
RequestMappingHandlerMapping mapping = super
.repositoryExporterHandlerMapping();
mapping.setInterceptors(new Object[] { new MyInterceptor() });
return mapping;
}
It worked perfectly fine for me. But when i upgraded to spring-data-rest-webmvc 2.3.0 version, I noticed that handlerMapping is hidden behind DelegatingHandlerMapping. Hence I tried to add interceptor in following way.
In one of my config class I have extended RepositoryRestMvcConfiguration class & override its method.
public class AppConfig extends RepositoryRestMvcConfiguration {
#Autowired ApplicationContext applicationContext;
#Override
public DelegatingHandlerMapping restHandlerMapping()
{
RepositoryRestHandlerMapping repositoryMapping = new RepositoryRestHandlerMapping(super.resourceMappings(), super.config());
repositoryMapping.setInterceptors(new Object[] { new MyInterceptor()});
repositoryMapping.setJpaHelper(super.jpaHelper());
repositoryMapping.setApplicationContext(applicationContext);
repositoryMapping.afterPropertiesSet();
BasePathAwareHandlerMapping basePathMapping = new BasePathAwareHandlerMapping(super.config());
basePathMapping.setApplicationContext(applicationContext);
basePathMapping.afterPropertiesSet();
List<HandlerMapping> mappings = new ArrayList<HandlerMapping>();
mappings.add(basePathMapping);
mappings.add(repositoryMapping);
return new DelegatingHandlerMapping(mappings);
}
}
But after adding this some of my repository operations (findAll() operation on repository) start failing. If I removed this interceptors those operations worked fine. (In this interceptor I am just authenticate the user.)
Hence I am unable to understand problem here. Am I adding the interceptor in wrong way? Is there any other way to add the interceptor?
You should not use repositoryMapping.setInterceptors() - it destoys the internal interceptors Spring placed there, and that's probably the reason some methods stopped working.
I suggest you override jpaHelper() method and put your interceptors into the JpaHelper object in RepositoryRestMvcConfiguration. Spring will should them to the global interceptor list.
But, again, if all you need is authentication, why not use a Spring Security filter?
EDIT: the solution above works only for RepositoryRestHandlerMapping, not for BasePathAwareHandlerMapping.
I suggest you declare a custom MappedInterceptor bean somewhere:
#Bean
public MappedInterceptor myMappedInterceptor() {
return new MappedInterceptor(new String[]{"/**"}, new MyInterceptor());
}
From my understanding of the source code Spring should automatically add this interceptor to all request handlers.

Inject EJB into JAX-RS 2.0 subresource when subresource is got via ResourceContext

I am using Jersey 2.8 with Glassfish 4.0.
I have a resource locator class which looks like below
#Path("/")
#ManagedBean
public class MyServiceLocator {
#Context
ResourceContext rc;//javax.ws.rs.container.ResourceContext
#EJB
private MyEJBHome myEJB;
#Inject//javax.inject.Inject
MySubService mss;
#Path("/mysubservice")
public MySubService getMySubService() {
return rc.getResource(MySubService.class);
//also tried return rc.initResource(new MySubService());
}
}
and a sub resource class which is
#ManagedBean
public class MySubService {
#EJB
public MyEJBHome myEJB;
#Context
HttpHeaders heads;
/*#Inject
private myEJBHome myEJB2;*/
#Path("/mypath")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Object doSomething(#Context SecurityContext securityContext) {...}
}
beans.xml file is put to META-INF and WEB-INF.
In MyServiceLocator class private MyEJBHome myEJB is injected successfully. And MySubService mss object is injected successfully and with EJB injected into it.
The problem is that when MySubService is got via ResourceContext the EJB is not injected into it.
Previously i used Glassfish 3 and Jersey 1.17 with proprietary ResourceContext and absolutely the same code worked ok.
I googled a lot and read a lot of similar (but a bit different) questions and as i understood non JAX-RS stuff (EJB in my case) can't be injected when sub resource is got via ResorceContext. Is it true? If yes how can i work it around?
The one possible solution is to inject sub resource objects to the resource locator class but there are too many of them and it seems to be very ugly.
EDIT Injection with #Inject works if to create a binder, bind ejb class to ejb interface and register that binder. But i don't want to describe binding for hundreds of my ejbs. Also as i understand it is specific binding fir HK2 system and i don't want to be linked to it.
Different actions with setting #Named annotations and trying to inject via CDI didn't help. It seems that when getting sub-resource via ResourceContext Jersey uses only HK2 and that's why CDI can't do it's work. Is that correct?
The only appropriate solution i found was to create my own annotation and inject provider.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface EJBInject {
String beanName();
}
#Provider
public class EjbInjectProvider implements InjectionResolver<EJBInject> {
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
try {
String beanName = injectee.getParent().getAnnotation(EJBInject.class).beanName();
return new InitialContext().lookup("java:global/MyApp/" + beanName);
} catch (Exception e) {
return null;
}
}
#Override
public boolean isConstructorParameterIndicator() {
return false;
}
#Override
public boolean isMethodParameterIndicator() {
return false;
}
}
Then ejb can be injected using that annotation like
#EJBInject(beanName="MyBean")
MyBeanEJBHome myBean;
In such case any standard EJB injections which MyBeanEJBHome might need work correctly, too.

An EJB is in a JAR but is not found by the WAR next to in in an EAR

I have the structure described below, but I cannot make it so MyWebService has its member myService not null. The code of MyWebService is properly executed when I call the webservice. When I look at the JBoss logs, I keep seeing that MyServiceBean has several JNDI bindings allocated to it.
So how do I bind MyServiceBean to MyWebService?
Thanks!
my-ejb.jar:
#Local
public interface MyServiceBeanLocal {
...
}
#Stateless
public class MyServiceBean implements MyServiceBeanLocal {
...
}
my-web.war:
#Webservice(...)
public class MyWebService {
#EJB
MyServiceBeanLocal myService;
...
}
my-ear.ear:
* my-ear.ear
|-* my-web.war
|-* my-ejb.jar
Have you tried using MyServiceBeanLocal as a Remote interface ? You are trying to use dependency injection from a Web module and for a Local Interface .This is not actually suggested. Anyway, At first try to make the interface #Remote . If still it doesn't work try to use`Remote Look up from the Web module for your Remote interface link
I use CXF. CXF is not an EJB container, hence the issues I got.
I had to manually bind the EJBs, using their full name.