Eclipse MicroProfile Metrics with SOAP-based web services - eclipse

Isn’t it possible to use Eclipse MicroProfile Metrics with SOAP-based web services on Payara Server 5.193.1? #Counted and #Timed don’t seem to work with #WebService and #WebMethod? Although, #Metric works. Is this by design or is it an issue?
Here is my code:
Interface:
package nl.tent.laboratory.emp.metrics;
import javax.jws.WebMethod;
import javax.jws.WebService;
#WebService
public interface MyWebService {
#WebMethod
String sayHello();
}
Implementation:
package nl.tent.laboratory.emp.metrics;
import javax.jws.WebService;
import org.eclipse.microprofile.metrics.annotation.Counted;
#WebService(endpointInterface = "nl.tent.laboratory.emp.metrics.MyWebService")
public class MyWebServiceImpl implements MyWebService {
// #Inject
// #Metric
// Counter counter;
public MyWebServiceImpl() {
super();
}
#Counted(name = "myCounter")
#Override
public String sayHello() {
// counter.inc();
return "Hello Marc!";
}
}

#Counted
and #Timed
are method interceptors and work only on CDI beans. #Metric
injects metrics objects and works where injection is supported, including Servlets and Web services.
In Payara Server, a web service object is implemented as a servlet by default. Servlets can inject CDI beans but they aren't CDI beans themselves and CDI interceptors don't work on them.
You need to turn your WS into a CDI bean (e.g. with #RequestScoped) or EJB (#Stateless) to enable the Metrics interceptors.

Related

Wildfly 10 JAX-RS REST Service is not working - Result 404 not found

I want to create a simple JAX-RS REST Service for Wildfly 10. My issue is that my REST Service is not found. Result in browser is 404 not found. I am not sure what exactly the issue is. I get no error or exception in wildfly log file. I am using eclipse neon 3 and wildfly 10. My project is using JAX-RS not resteasy.
Here my project setup and code:
I have created a Dynamic Web Project in Eclipse.
I have set JAX-RS(REST Service) support in the project facets. JAX-RS version is 2.0 (also tried with version 1.1)
I have create a subclass which extends Application (javax.ws.rs.core.Application)
I added the annotation #ApplicationPath("/yoshi-rest") to the class which extends Application.
I have created a class which contains my rest service method. The class itself has the #Path("/StatusService") annotation.
The affected method has the annotations #Get and #Path("/getStatus").
Due to I have the subclass of Application I didn't set the servlet mapping in web.xml.
Here the code:
Subclass of Application(RESTConfig):
#ApplicationPath("/yoshi-rest")
public class RESTConfig extends Application {
}
REST Service class(StatusService):
#Path("/StatusService")
public class StatusService {
#Get
#Path("/getStatus")
public String getStatus() {
return "Yoshi is up and running";
}
}
I can see during startup of wildfly that the subclass RESTConfig is deployed:
11:09:23,777 INFO [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 61) RESTEASY002225: Deploying javax.ws.rs.core.Application: class XXXX.yoshi.rest.services.RESTConfig
If I call the rest service url (http://localhost:8080/yoshi-rest/StatusService/getStatus) in browser, I get a '404 - Not found' as result.
Any idea what I am doing wrong?
You need to register service to connect to your RESTConfig:
#ApplicationPath("/yoshi-rest")
public class RESTConfig extends ResourceConfig {
public RESTConfig() {
register(StatusService.class);
}
See more on ResourceConfig configuration options
Standard JAX-RS uses an Application as its configuration class. ResourceConfig extends Application.
Putting the project name in the url solved the issue.
Thanks for help.

How to integrate Keycloak with Payara Micro?

How i can integrate the Keycloak with Payara Micro?
I want create an stateless REST JAX-RS application that use the Keycloak as authentication and authorization server, but i unknown how do it.
The Eclipse MicroProfile JWT Authentication API defines the #LoginConfig annotation:
#LoginConfig(authMethod = "MP-JWT", realmName = "admin-realm")
#ApplicationPath("/")
public class MyApplication extends Application {...}
And the java EE the #RolesAllowed annotation:
#Path("/api/v1/books")
public class BooksController {
#GET
#RolesAllowed("read-books")
public Books findAll() {...}
}
How integrate these two things?
Keycloak project doesn't provide a native adapter for Payara Server or Payara Micro and the Payara project doesn't provide it either.
But Keycloak also provides a generic servlet filter adapter which should also use with Payara Micro: https://www.keycloak.org/docs/latest/securing_apps/index.html#_servlet_filter_adapter
Just add the keycloak-servlet-filter-adapter dependency into your web application and configure the adapter in the web.xml according to the documentation. I haven't tested it though, so I don't know if it really works.
I faced the same challenge in a personal project and as is mentioned Keycloak project does not provide a native adapter for Payara, in that moment I did a library to secure my app with Keycloak, if you like, you can take it a look and let me know if it's ok or how we can improve it.
https://github.com/pablobastidasv/kc_security
You can find solution in The Payara Monthly Roundup for April 2019
MicroProfile JWT with Keycloak - In this step by step blog, Hayri Cicek‏ demonstrates how to secure your services using MicroProfile JWT and Keycloak.
Init LoginConfig and map your roles using DeclareRoles
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import org.eclipse.microprofile.auth.LoginConfig;
import javax.annotation.security.DeclareRoles;
#LoginConfig(authMethod = "MP-JWT")
#ApplicationPath("/")
#DeclareRoles({ "mysimplerole", "USER" })
public class ApplicationConfig extends Application {
}
Add params to microprofile-config.properties
mp.jwt.verify.publickey.location=http://localhost:8084/auth/realms/public/protocol/openid-connect/certs
mp.jwt.verify.issuer=http://localhost:8084/auth/realms/public
And you can use your roles in RolesAllowed
#ApplicationScoped
#Path("/hello")
public class HelloWorldEndpoint {
#GET
#Produces("text/plain")
#RolesAllowed("mysimplerole")
public Response doGet() {
return Response.ok("Hello from MicroProfile!").build();
}
}

java ee lookup ejbs from from different app

Java EE Tutorial is not helpful at all. Internet search was underwhelming.
I have an EJB module that is deployed to glassfish by itself. It has #Local and #Remote annotated iterfaces which are both implemented by the concrete class.
Then i have a REST resource that needs to get a reference to that ejb module and invoke some methods.
Can you give me a barebones, simple example of how that is done? I mean, i can't even inject SessionContext into my rest app, as it crashes... Please, keep it simple.
The ejb should just have a:
public String getMsg(){
return "ohai";
}
The rest service:
#GET
#Produces("text/plain")
public String asd(){
return <the myterious ejb that was injected somehow>.getMsg();
}
Thanks.
Alright, i figured it out. Using NetBeans, but probably applicable to Eclipse. Server - glassfish
Create webapp, an EJB -> call EJB from webapp. All these run inside the same server as separate modules.
First: create an EJB module, it will be deployed on its own:
remote interface:
package main;
import javax.ejb.Remote;
#Remote
public interface YourRemoteInterface{
public String tellMeSomething();
public void otherMethod(); //etc...
}
then create the EJB implementation class:
concrete implementation
package main;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.EJB; //crucial to JNDI lookup
#Remote(RemoteInterface.class)
#Stateless
#EJB(name="java:global:/MYSTUFF", beanInterface=YourRemoteInterface.class)
public class YourConcreteClass implements YourRemoteInterface{
#Override
public String tellMeSomething(){//...} //and do the other methods
}
#EJB name attribute names your bean, that you will use to look it up. Can by any name. For ex: "some-name", or "java:global/YourConcreteClass"
Part two - webapp:
For web app i used a rest service, but surely can be another EJB or a SE client app. For SE client you'd need to set connection info, but that for another life.
#Path("/somePath")
public class Service{
#GET
#Produces("text/plain")
public String qwe(){
try{
javax.naming.InitialCOntext ic = new javax.naming.InitialContext();
YourRemoteInterface rb = (YourRemoteInterface)ic.lookup("java:global:/MYSTUFF");
return rb.tellMeSomething();
} catch (Exception ex) {
return "F*uck your life";
}
}
}
Now, from Project Properties of your webapp, you need to:
1) add the ejb jar file to Libraries so it shows in the Compile tab. I used the "Add project" button
2) Build -> Packaging: add the ejb jar file to WAR content. I used "Add file/folder", where i navigated to NetBeans projects / the EJB module / build / dist
note: you may experience an error when trying to deploy the ejb, or redeploy it. Error name is: java.lang.RuntimeException: Error while binding JNDI name main.RemoteInterface#main.RemoteInterface for EJB RemoteBean . Skipping the vague explanation, to cure it, you need to execute a command in glassfish:
asadmin set server.ejb-container.property.disable-nonportable-jndi-names="true"
Now, you can compile the webapp and deploy it. Should work.
At the end it's that simple. I swear i've eaten the WHOLE ejb section in glassfish tutorial and nowhere do they tell you this stuff. It's so annoying.

Unable to create Spring AOP aspect on Spring Data JPA Repository when CGLIB proxies are used

I'm trying to apply an aspect on a Spring Data JPA Repository and it works fine with default Spring AOP config
#EnableAspectJAutoProxy
(when Spring uses standard Java interface-based proxies).
However, when I switch to CGLIB proxies:
#EnableAspectJAutoProxy(proxyTargetClass = true)
I get this exception:
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy59]:
Looks like Spring tries to wrap a CGLIB proxy on a repository class, which is already a CGLIB proxy (generated by Spring Data) and fails.
Any ideas how to make it work?
My Spring Data Repository:
import org.springframework.data.jpa.repository.JpaRepository;
public interface DummyEntityRepository extends JpaRepository<DummyEntity, Integer> {
}
and the aspect:
#Aspect
public class DummyCrudRepositoryAspect {
#After("this(org.springframework.data.repository.CrudRepository)")
public void onCrud(JoinPoint pjp) {
System.out.println("I'm there!");
}
}

NPE when #Inject #Stateless service in a JAX-RS class in JBoss EAP 6.2

I've got that JAX-RS webservice:
#Path("/my")
public class MyWS {
#Inject
private MyService myService;
#POST
#Path("/save")
#Consumes("application/json")
public void save(SaveParam saveParam) {
myService.save(saveParam);
}
}
and that #Stateless service:
#Stateless
public class MyService {
#PersistenceContext
protected EntityManager entityManager;
#TransactionAttribute
public void save(SaveParam saveParam) {
entityManager.persist(saveParam);
}
}
Using JBoss EAP 6.2, myService is always null (not injected) when arriving in the save method.
I've tried to add #ApplicationScoped to MyWS class, but the same behavior is happening (NullPointerException). The only solution is to declare MyWS also as #Stateless, but that's not really have any sens, have it?
Is this a bug in JBoss EAP?
All my classes are in the same war project and I have a WEB-INF/beans.xml using CDI 1.0 spec. I also have a class extending javax.ws.rs.core.Application and declaring the #ApplicationPath.
I guess it is a bug if you configure your REST service in web.xml.
I have the same issue and i was getting crazy about this.
Just clean up the web.xml and it should not have anything related to REST.
#ApplicationPath is good enough for all REST setup.