This is a clarification question I've got from a Java EE 5 migration. I'm currently developing a Java EE 6 web service packed in a WAR file, and I would like to know if it's possible to use CDI on it. I've seen some examples using the #Stateless annotation, which it's not possible to do in a WAR (as far as I know).
Current implementation:
#WebService
public class MyService{
#Inject
HelloTeller teller:
#WebMethod
public String sayHello(){
teller.sayHello();
}
}
Note: The other approach would be to create an ejbModule specifically for this web-service.
In EE6, you should be able to use a SLSB as JAX-WS endpoint in a war. You can inject EJBs, request scoped and application scoped beans from CDI.
Related
My application should show a list of stuff over RESTful WebServices.
This list of stuff is generated via an EJB which is deployed in JBoss AS 6 in a .jar.
My question is, how do I get this list of stuff in order to show it via Web Services?
If I try to inject #EJB in the stateless bean annotated with #WebService, and try to invoke the method that generates the list, I get an error saying that #EJB cannot be resolved (or imported). (fixed it, needed to modify maven dependencies).
Now I get a NullPointerException when I call the supposedly injected EJB...
I am using the webapp archetype from Maven, which contains an EAR, a JAR and a WAR.
I am at a total loss here, been trying to figure this for almost a week.
Thanks in advance!
--EDIT-- code and typo fixed
This is my stateless bean which SHOULD be exposed as a WebService (according to:
http://www.adam-bien.com/roller/abien/entry/restful_calculator_with_javascript_and )
#Stateless
#Path("/MyRESTApplication")
public class HelloWorldResource {
#EJB
private TestBean testBean;
#GET()
#Produces("text/plain")
public String sayHello(String name) {
return testBean.doMoreStuff();
}
}
the doMoreStuff() function simply returns "HELLO!".
I want to deploy an EJB 3.0 stateless bean to WAS7 so I can access it as an EJB through a local interface and also as a jax-ws web service.
My bean looks as following:
#Stateless
#WebService
public class UserManagerImpl implements UserManager {
public UserManagerImpl() {
}
#WebMethod
public String getName(){
return "UserName";
}
}
The problem is that if I package it into an EJB-JAR and deploy, it doesn't work as a web service on WAS-7.
The only working configuration for me is if I put the EJB-JAR into a EAR and put this EJB-JAR to a WAR that is also in the EAR, like this:
EAR/
|--EJB-JAR
|--WAR/
|WEB-INF/lib/
|EJB-JAR
So my bean is duplicated.
Is there any problem with this design? If so, is there a better solution?
If your application contains #WebService annotated EJBs, then you need to process the EAR with the endptEnabler tool shipped with WebSphere before deploying it. Note that this doesn't apply to #WebService annotated classes in Web modules.
I want to export a Web-Service which was implemented as a stateless EJB. I know that these WebServices were hanled by the EJB Container, when they are annotated as #Stateless + #Webservice. Is it possible to route all incoming requests to this Webservice through a Servlet-Filter.
The Servlet-Filter works when my Java-Class is annotated #Stateful and #Webservice, or just #Webservice. But not in conjunction with #Stateless. Anyway to register a Servlet Filter for an EJB Webservice?
Many thanks!
Adem
UPDATE:
Solved this problem, by annotating WebService Class with
#WebService
#RequestScoped
Filter works only in this constellation and acting as Stateless class for WebService consumer.
Lifecycle Callbacks : You can have a method with #PostConstruct annotation which gets called after the container has initialized the bean.
Interceptor : You can have a interceptor class which gets invoked when applied at bean class/method level by annotation #Interceptors(ProcessMonitor.class).
Note : I haven't tried it in conjunction with #Webservice.
Is it possible to use #RolesAllowed annotation on a JAX-WS webservice and if so how?
I have a webservice on glassfish 3.1.1 using Basic Authentication but restrictions expressed using #RolesAllowed are ignored. The role information should be available, as I can access it like this:
#Resource
WebServiceContext wsContext;
if (wsContext.isUserInRole("READ"))
log.info("Role: READ");
I get the expected role but still all methods are accessible, even if #RolesAllowed is set to different role. #DenyAll is not working as well.
If these annotations are not supported, is it possible to use deployment descriptors to manage access to webservice methods based on user roles?
Edit:
This part of the JAVA EE 6 tutorial describes the usage of #RolesAllowed annotation. It reads
For Java EE components, you define security roles using the #DeclareRoles and #RolesAllowed metadata annotations.
Web services are not listed as Java EE components in the first part of the tutorial, so it looks like the security annotations are not supported.
Edit2
Following Izan's post, I gave this another try. Here is what I did:
#Webservice
#DeclareRoles(value = {"READ", "UPDATE", "DELETE"})
public class ServiceImpl implements Service {
#Override
#WebMethod(operationName = "helloWorld")
#RolesAllowed({"NONE"})
public String helloWorld() throws Exception {
return "Hello World!";
}
}
Using this kind of setup, everybody can access the method, no matter what roles are set. Users get authenticated (can see that in audit.log) but no authorization takes place. As stated above, I can access the role from WebServiceContext (I actually do manual authorization using this info).
Adding #Stateless annotation, let's me use the security annotations. So #permitAll works as expected. But using roles still does not work, as user don't get authenticated now. They show up as ANONYMOUS in audit log and access is denied to them.
My web.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>OneMore</display-name>
<security-constraint>
<display-name>WebServiceSecurity</display-name>
<web-resource-collection>
<web-resource-name>Authorized users only</web-resource-name>
<url-pattern>/service</url-pattern>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>READ</role-name>
<role-name>UPDATE</role-name>
<role-name>DELETE</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>READ</role-name>
</security-role>
<security-role>
<role-name>UPDATE</role-name>
</security-role>
<security-role>
<role-name>DELETE</role-name>
</security-role>
</web-app>
Glassfish-web.xml just maps role names to group names, like this:
<security-role-mapping>
<role-name>READ</role-name>
<group-name>READ</group-name>
</security-role-mapping>
Edit 3
Thanks to Izan and countless tries later I finally got it working.
As said before, the main point was switching from a plain web service to an EJB web service by adding #Stateless annotation. This allows for using the security annotations.
This change required to change the deployment descriptors as well. While the original web service required a glassfish-web.xml for setting up the roles, a glassfish-ejb-jar.xml is required afterwards.
Maybe this is a pretty dumb question, but are your webservices EJBs? As noted in Security Annotations and Authorization in GlassFish and the Java EE 5 SDK
The annotations #PermitAll, #DenyAll and #RolesAllowed are defined for specifying permissions of EJB business method
I use those annotations with bottom-up WS from stateless EJBs and they work like a charm in JBoss.
EDIT 1 #TPete
I'll add some code to show you more or less what I'm doing.
#Stateless
#WebService()
#WebContext(contextRoot = WSContextRoot.CTX_ROOT,
authMethod = "BASIC")
#EndpointConfig(configName = "Standard WSSecurity Endpoint")
#SecurityDomain(value = "myDeclaredDomain")
#RolesAllowed({ "AUTHORISED" })
#SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
public class MyWS implements MyInterface {
#Override
public void doSomething(){
//impl
}
}
And as for the interface
#Remote
#WebService
public interface MyInterface {
#WebMethod(operationName="doSomething")
public void doSomething();
}
WebContext, EndpointConfig and SecurityDomain are JBoss annotation, but I suppose there is something similar for GlassFish, or an equivalent way of doing it. The security domain is included in a deployment descriptor for jboss, and defined in the login-config.xml from the configuration files of JBoss.
EDIT 2 #TPete
I suppose you need to add some EJB deployment descriptors from Glassfish, a sun-ejb-jar.xml file package inside your EAR. Again, from the same article as posted in the answer, there is a Using Deployment Descriptors chapter that states
For EJB web service endpoints with #RolesAllowed, you need to specify the type of authentication to use by specifying the and elements in sun-ejb-jar.xml. For username-password authentication, set the element to BASIC, as shown in the following example. This step is required only for EJB web service endpoints, and is not required for EJBs.
Since you are defining an EJB web service endpoint, I think you should put this descriptor in you EAR. Have a quick look at that article, it describes quite well the process you are following :-)
The original question is old but I'm still leaving a comment just in case someone like me stumbles across it. Starting with EJB 3.1, EJBs may be packaged in a WAR module but when it comes to securing them, EJB deployment descriptors need to be used. What is not clear in the spec is that EJBs may not be declared as Servlets in web.xml or else the app will fail to start.
Here's an excellent article about packaging EJBs in WAR modules and the differences with packaging in EJB JAR modules:
http://pic.dhe.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=%2Fcom.ibm.websphere.nd.multiplatform.doc%2Finfo%2Fae%2Fae%2Fcejb_ejbinwar.html
i have a local client j2se application and backend is derby(javadb) database and dao is jpa eclipselink .
how do i send these database pojo to a remote database which linked with spring ( jsp) application on tomcat server
simply this is a rich client with swing which connects to tomcat deployed web application. The client should receive data and send data through HTTP requests to the server-side of the service,
what would be the best solution ??
01) direct database connection/transaction through socket using Eclipselink
02) web service ??
03) just send post request to spring web application and convert it to POJO and persist to database
how do i achieve this??
DISCLAIMER I am not suggesting you port your app from Spring to EJB. Despite how people like to compare them as exclusively one or the other, you can use them both. Its your app, you can be as pragmatic as you want to be :)
You don't necessarily have to use Web Services if you wanted. You could drop the OpenEJB war file into Tomcat as well and create an Remote EJB to send data back and forth.
Once you drop in OpenEJB you can put a remote #Stateless bean in your app like so:
#Stateless
#Remote
public class MyBean implements MyBeanRemote {
//...
}
public interface MyBeanRemote {
// any methods you want remotely invoked
}
Then look it up and execute it over HTTP from your Swing app like so:
Properties p = new Properties();
p.put("java.naming.factory.initial", "org.apache.openejb.client.RemoteInitialContextFactory");
p.put("java.naming.provider.url", "http://tomcatserver:8080/openejb/ejb");
// user and pass optional
p.put("java.naming.security.principal", "myuser");
p.put("java.naming.security.credentials", "mypass");
InitialContext ctx = new InitialContext(p);
MyBean myBean = (MyBean) ctx.lookup("MyBeanRemote");
Client-side all you need are the openejb-client.jar and javaee-api.jar from the OpenEJB war file and your own classes.
Since it's already a Spring app don't bother trying to use #PersistenceContext to get a reference to the EntityManager so the EJB can use it. Just figure out how to expose the EntityManagerFactory that Spring creates (or you create) to the EJB via any means possible. The direct and ugly, but effective, approach would be a static on the MyBean class and a bit of startup logic that sets it. You'd just be using the EJB for remoting so no need for fancier integration.
If you did really need web services for non-java communication or something, you can add #WebService to the top of your bean and then it will have WSDL and all that generated for it:
#Stateless
#Remote
#WebService(portName = "MyBeanPort",
serviceName = "MyBeanService",
targetNamespace = "http://superbiz.org/wsdl"
endpointInterface = "org.superbiz.MyBeanRemote")
public class MyBean implements MyBeanRemote {
//...
}
public interface MyBeanRemote {
// any methods you want remotely invoked
}
Then you can also use the same bean as a web service like:
Service service = Service.create(
new URL("http://tomcatserver:8080/MyBeanImpl?wsdl"),
new QName("http://superbiz.org/wsdl", "MyBeanService"));
assertNotNull(service);
MyBeanRemote myBean = service.getPort(MyBeanRemote.class);
Both approaches are over http, but the web service approach will be a bit slower as it isn't a binary protocol.