How to call EJB 3.0 by external Servlet - java

I am learning EJB 3 and trying some simple stuff on it.
I am using eclipse -> Luna Service Release 1 (4.4.1) with JBOSS AS 7.1.1 (final)
I created a simple EJB project in eclipse with name -> SalutationEJBProj. Under this project created a simple session, stateless Bean.
code:
package com.vipin.bean.session.stateless;
import javax.ejb.Stateless;
#Stateless(mappedName="SalutationBean")
public class SalutationBean implements SalutationBeanRemote {
public SalutationBean() {
}
#Override
public String getFormalSalutation(String name) {
return "Dear" + name;
}
#Override
public String getInfomalSalutation(String name) {
return "Hi" + name;
}
}
The Remote interface is:
package com.vipin.bean.session.stateless;
import javax.ejb.Remote;
#Remote
public interface SalutationBeanRemote {
public String getFormalSalutation(String name);
public String getInfomalSalutation(String name);
}
I am able to deploy it in Jboss AS 7.1.1 and here is the JNDI bindings output when i start the jboss:
java:global/SalutationEJBProj/SalutationBean!com.vipin.bean.session.stateless.SalutationBeanRemote
java:app/SalutationEJBProj/SalutationBean!com.vipin.bean.session.stateless.SalutationBeanRemote
java:module/SalutationBean!com.vipin.bean.session.stateless.SalutationBeanRemot
java:jboss/exported/SalutationEJBProj/SalutationBean!com.vipin.bean.session.stateless.SalutationBeanRemote
java:global/SalutationEJBProj/SalutationBean
java:app/SalutationEJBProj/SalutationBean
java:module/SalutationBean
Now, i want this ejb to be accessible by an external Servlet, for this I created a dynamic web project with name --> SalutationServletProj
Here is the code of the simple Servlet:
package com.vipin.servlet;
#WebServlet(urlPatterns = { "/SalutationServlet" })
public class SalutationServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
private SalutationBean salutationBean; // <-- How will this be accessible, this is in a different project, how do we import this?
public SalutationServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
My intention is to use #EJB annotation (or any other method) to get the instance of the EJB in the Servlet.
As these two are in different projects, how can i achieve this? I can't use like this in servlet:
import com.vipin.bean.session.stateless.SalutationBean
1) What are the files from EJB project that i have to copy into servlet project.
2) Will it work as #EJB annotation or do i need to do JNDI lookup? (Because the servlet is remote).
3) Where can i find the classes/libraries generated in jboss?
Any help highly appreciated.

it should be sufficient to only add the SalutationBeanRemote into WEB-INF/classes of your web project.
Then it should work out if you add the following member to your Servlet:
#EJB(lookup="java:global/SalutationEJBProj/SalutationBean")
private SalutationBeanRemote salutationBean;
Only the java:global... names will work because your servlet is running in another module and application as the EJB.
I am unsure if the java:jboss/exported... lookup name works or if it is only for remote clients.
Best regards,
Robert

Related

How to setup Jetty Server in a Dropwizard project?

Recently I've started developing with Java, and was introduced to the Dropwizard framework. But what's got me stumped here, is that I'm not getting any resources online which would explain how to set it up a Jetty server with my Dropwizard application (I previously made use of Apache Tomcat, but was told that Jetty is a much better alternative). Also, what is use of Embedded-jetty in it?
(I realize that the nature of the question is rather amateurish, but I couldn't come across any online resource that would explain this succinctly :( ...)
The application part:
import io.dropwizard.Application;
public class App extends Application<AppConfiguration> {
public static void main(String[] args) throws Exception {
new App().run(args);
}
#Override
public void run(AppConfiguration configuration, Environment environment) {
final AppResource resource = new AppResource();
environment.jersey().register(resource);
}
The resource with a dummy API to get version:
public class AppResource {
#GET
#UnitOfWork(readOnly = true)
#Path("/version")
#ApiOperation(
value = "Retrieve the version")
#Timed
public Version getVersion() {
return new Version();
}
}

shared classloader with embedded Tomcat 8

I have upgraded tomcat from version 7.0.34 to version 8.0.33, and since then I have been facing a problem to share the web application context and Junit context.
I have a web application with singleton class that gathers statistic data about the web application. I also have Junit that runs the web application in embedded tomcat. the Junit queries the web application and then checks the statistic data.
I try to make a simple example:
the singleton:
public class Counter {
private static Counter instance;
private AtomicLong counter;
private Counter(){}
public static Counter getInstance(){
if(instance == null){
synchronized (Counter.class) {
if(instance == null){
instance = new Counter();
}
}
}
return instance;
}
public long incrementAndGet(){
return counter.incrementAndGet();
}
public long getValue(){
return counter.get();
}
}
the servlet:
#WebServlet(name="servlet",loadOnStartup=1, urlPatterns="/servletTest")
public class Servlet extends HttpServlet{
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hi, you are the #" + Counter.getInstance().incrementAndGet() + " visitor");
}
}
contextListener:
public class MyContextListener implements ServletContextListener{
#Override
public void contextDestroyed(ServletContextEvent arg0) {}
#Override
public void contextInitialized(ServletContextEvent arg0) {
Counter.getInstance().incrementAndGet();
}
}
Test unit:
public void mainTest() throws ServletException, LifecycleException{
Tomcat tomcat = new Tomcat();
tomcat.setPort(50000);
StandardContext ctx = (StandardContext) tomcat.addWebapp("/fe", System.getProperty("FEBaseDir")); //The FEBaseDir property is supposed to be taken from Maven build using 'test' profile
tomcat.start();
Counter.getInstance().getValue();
}
when I used Tomcat 7, everything worked fine. but since I upgraded tomcat to tomcat 8.0.33, It hasn't been working. the singleton class with the static data loads twice. first by the tomcat and then by the Junit itself.
I have tried to pass tomcat a classloader but it doesn't work.
public void mainTest() throws ServletException, LifecycleException{
Tomcat tomcat = new Tomcat();
tomcat.setPort(50000);
StandardContext ctx = (StandardContext) tomcat.addWebapp("/fe", System.getProperty("FEBaseDir")); //The FEBaseDir property is supposed to be taken from Maven build using 'test' profile
ctx.setCrossContext(true);
ctx.setLoader((Loader) new WebappLoader(Thread.currentThread().getContextClassLoader()));
ctx.setParentClassLoader(Thread.currentThread().getContextClassLoader());
tomcat.getEngine().setParentClassLoader(Thread.currentThread().getContextClassLoader());
tomcat.getHost().setParentClassLoader(Thread.currentThread().getContextClassLoader());
tomcat.getService().setParentClassLoader(Thread.currentThread().getContextClassLoader());
tomcat.getServer().setParentClassLoader(Thread.currentThread().getContextClassLoader());
tomcat.start();
Counter.getInstance().getValue();
}
What am I doing wrong?
You could try using the setDelegate method in StandardContext to prevent the web-app classloader from reloading the Counter class, but this impacts security in a bad manner so I advice against that.
The usual way to expose statistics is to use JMX (MBeans). You enable this by calling the setUseNaming method in StandardContext with value true.
You can register a mbean like this (copied from here):
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName beanPoolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + poolName + ")");
mBeanServer.registerMBean(hikariPool, beanPoolName);
And you can retrieve a value like this (copied from here):
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (foo)");
HikariPoolMXBean poolProxy = JMX.newMXBeanProxy(mBeanServer, poolName, HikariPoolMXBean.class);
int idleConnections = poolProxy.getIdleConnections();
See also this SO question and you'll probably have to read some more documentation (in my experience, it takes a while to understand the whole JMX thing and get it to work). I have not tried this in combination with unit-tests though, so YMMV.

How to deliver Realm with the war with Tomcat?

we have a simple web application running on Tomcat 7.0.56. Now we want to use our
own realm for authentication.
public class SpecialAuth extends DataSourceRealm{
#Override
public Principal authenticate(String username, String credentials){
....
}
}
This is defined in the /META-INF/context.xml inside the war
<Context>
<Realm className="some.package.SpecialAuth" dataSourceName="jdbc/MySQL" />
</Context>
Where to put the SpecialAuth.class?
What we expected was simply to have the SpecialAuth.class inside our war but then we're getting folling exception on startup
Caused by: java.lang.ClassNotFoundException: some.package.BackOfficeAuth
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
....
If we make a jar, putting it into $TOMCAT/lib everything works fine.
But this CAN'T be the solution! That would mean every time I work on this class(es) I have to touch my tomcat server and can't use the normal deployment.
How can I use the build-in authentication mechanism without touching the tomcat all the timeß
As you said I don't like your answers :) So what I did (and I'm 100% sure that you don't like it) was to set the realm on the dirties possible way BUT now I can run it on a ontouched tomcat. After 163 acceptance tests nothing seems to break.
public final class ContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
TomcatContextManipulator tomcat = new TomcatContextManipulator(servletContext);
tomcat.applyRealm(new MyOwnRealm());
}
}
.
public class TomcatContextManipulator {
private static final String EXPEXCTED_TOMCAT_VERSION = "7.0.52.0";
private ApplicationContextFacade servletContext;
/**
* #param servletContext must be of type {#link ApplicationContextFacade}
*/
public TomcatContextManipulator(ServletContext servletContext) {
checkTomcatVersion();
ensureEquals(servletContext.getClass(), ApplicationContextFacade.class, "class of servletContext");
this.servletContext = (ApplicationContextFacade) servletContext;
}
/**
* checks if the correct version of tomcat is in use, throws {#link IllegalStateException} if not
*/
private void checkTomcatVersion() {
// we use several internal parts of tomcat (for example with reflection)
// by doing this we bind ourself hardly to a explicit version
ensureEquals(EXPEXCTED_TOMCAT_VERSION, ServerInfo.getServerNumber(), "Tomcat-Server-Version");
}
/**
* overrides the existing realm with the given on
*/
public void applyRealm(Realm realm) {
ensureNotNull(realm, "realm");
ApplicationContext applicationContext = (ApplicationContext) ReflectionUtil.get(servletContext, "context");
StandardContext standardContext = (StandardContext) ReflectionUtil.get(applicationContext, "context");
standardContext.setRealm(realm);
}
}
Note:
Reflection.get() returns the value of the (private) instance variable of the given object
ensure...() is like assert... but it throws Exception

Atmosphere framework, BroadcasterFactory.getDefault() alternative

I am using Atmosphere framework and it looks in the newest version(s) of the library the method:
BroadcasterFactory.getDefault() is depricated. (and this method was essentially used everywhere and I cannot find an example how to use the new "way" )
The javadoc states :
#deprecated Use {#link org.atmosphere.cpr.AtmosphereConfig#resourcesFactory()}
However I cannot find a single documentation how to get the AtmosphereConfig to be able to get the resourceFactory (which is an instance method).
Can someone tell me how to get the config .. or the AtmosphereFramework object itself from which I can get the config or any example which is up2date ?
Not sure if it works, but try to get ServletContext and use getAttribute(AtmosphereFramework.class.getName()) to obtain AtmosphereFramework. If you are using Spring, try to autowire AtmosphereFramework directly.
You can also get BroadcasterFactory from AtmosphereResource and then lookup for Broadcaster like:
private String path;
private BroadcasterFactory broadcasterFactory;
#Ready(value = Ready.DELIVER_TO.ALL)
public void onReady(final AtmosphereResource r) {
System.out.println("onConnect");
r.addEventListener(new AtmosphereConnectionController());
if(broadcasterFactory == null){
path = r.getBroadcaster().getID();
broadcasterFactory = r.getAtmosphereConfig().getBroadcasterFactory();
}
}
//later in code
broadcasterFactory.lookup(path).broadcast("message");
Use dependency injection. In my project, it goes like this:
#MeteorService(path = "/recursos/fila-de-atendimento", interceptors = {AtmosphereResourceLifecycleInterceptor.class})
public class FilaDeAtendimentoResource extends HttpServlet {
#Inject
private BroadcasterFactory broadcasterFactory;
...
/** Used for registering for a message */
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
...
Broadcaster broadcaster = broadcasterFactory.lookup(broadcasterId, true);
meteor.setBroadcaster(broadcaster);
...
}
}

jax-rs and server name

I am still working on a jax-rs server, and I faced some new problems recently. I do not understand where I define the name of my webserver. I searched everything in my workspace, but couldn't find anything.
Let's roll out the problem a bit further:
I always reach my server's #GET method via http://XXXXXX.XXXXX.XXX-XXXXXXX.de/android/
This is the structure of my server class:
#Path("/users")
public class UserResource {
Connection dbconn = null;
public UserResource() {
userIds = new ArrayList<Integer>();
userIds.add(1);
userIds.add(2);
userIds.add(3);
}
#GET
#Path("/login/{id}")
#Consumes("application/xml")
public StreamingOutput getTests(#PathParam("id") int id, InputStream is) {
return new StreamingOutput() {
public void write(OutputStream outputStream) throws IOException,
WebApplicationException {
getTests(outputStream);
}
};
}
As you see, the path of my class is "/users", and the path of the #GET method is "/login/1" (for example id = 1). Now I tried to call the method via
http://XXXXXX.XXXXX.XXX-XXXXXXX.de/android/users/login/1
But this does not work. I get an error (unknown source). And my error.log says that it couldn't find the resource at
http://XXXXXX.XXXXX.XXX-XXXXXXX.de/users/users/login/1
My 1st question: Where does the double "/users" come from? I have no idea. When I leave away the "/users" in my request url, there will be only 1 "/users" in the error.log, but still the resource is not found.
And there is another thing I did not find out yet: How do I change the name of my service? Atm, it's "android", but how could I change this? I searched my whole workspace, found "android" in my pom.xml, but when i change it to, let's say "testandroid", upload everything, build and run the server, the name is still android. No idea why this is the case.
Thx for your help guys!
EDIT:
This is my "main" class:
package com.restfully.services;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
public class ServerApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> empty = new HashSet<Class<?>>();
public ServerApplication() {
singletons.add(new UserResource());
}
#Override
public Set<Class<?>> getClasses() {
return empty;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
I am using Eclipse and Maven. The application runs on a jetty-server. If you could use any further information, let me know.
You can look in the following places
Pom.xml file for context root the following entry;
<configuration>
<context>yourWarName</context>
</configuration>
Using Netbeans check Run Category context path under project properties.
Context Path: /yourWarName
Have a look in your web.xml as well.
When using jax-rs you normally define a config class;
#ApplicationPath("resources")
public class RestConfig extends Application{
}
From there you define your other paths;
#Stateless
#Path("/login")
public class LoginResource
public Response login(Credentials credentials) {
Credentials result = this.loginService.login(credentials);
return Response.status(Response.Status.OK).entity(result).build();
}
The path to the following is: http://domain.com/MyApp/resources/login
where MyApp is the context root.
It might be that there is a path specified in config or root with the name users that you are getting the double users.

Categories