Can an EJB be called from a desktop application? - java

I am new in Java EJB 3.0. It is possible to call a (session) bean—deployed on JBoss—from a desktop application client?
Thanks in advance.

Yes you can. Some specifics are here (references EJB2 but it the same for EJB3 when it comes to remote clients): http://www.theserverside.com/discussions/thread.tss?thread_id=9197
Paraphrased:
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
env.put("java.naming.provider.url", "jnp://localhost:1099");
env.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
Context ctx = new InitialContext(env);
// name is whatever JNDI name you gave it
Object o = ctx.lookup("home name");
EJBHome ejbHome = (EJBHome) PortableRemoteObject.narrow(o,EJBHome.class);
// This is userID should be the one passed.
EJB ejb = ejbHome.create(..);

Yes.
public static void main(String args[]) throws Exception {
InitialContext ctx = new InitialContext();
YourService yourService = (YourService) ctx.lookup("com.example.session.YourService");
String time = yourService.getTime();
System.out.println("Time is: " + time);
}
For client configuration you must provide jndi.properties file with contents
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
If you are looking for working examples on JBoss try download source code of Enterprise JavaBeans 3.0, Fifth Edition

Let's assume you have the following remote interface:
#Remote
public interface HelloBeanRemote {
public String sayHello();
}
And a session bean implementing it:
#Stateless
public class HelloBean implements HelloBeanRemote {
...
}
And that this EJB is correctly packaged and deployed on JBoss.
On the client side, create a jndi.properties with the following content and put it on the classpath:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost:1099
Then use the following code to call your EJB:
Context context;
try {
context = new InitialContext();
HelloBeanRemote beanRemote = (HelloBeanRemote)context.lookup("HelloBean/remote");
beanRemote.test();
} catch (NamingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
Alternatively, if you don't want to provide a jndi.properties file, you can explicitly setup the JNDI environment in the code and create the context like this:
Properties properties = new Properties();
properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces");
properties.put("java.naming.provider.url","localhost:1099");
Context context = new InitialContext(properties);
But I'd recommend using the jndi.properties for the sake of portability.

You can also expose the bean as a web service. I believe this is available as of EJB 3. It is quite nice considering you can do it with annotations. You may wish to consider using this option to decrease coupling. Here is a link to a tutorial.

Related

Dependency injection into websocket endpoint on embedded jetty

I have a the following websocket endpoint:
import javax.inject.Inject;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint(value = "/blabla")
public class WebsocketService {
#Inject
private DatabaseProvider dbProvider;
#OnOpen
public void onOpen(Session session) throws IOException {
//do something
}
#OnMessage
public void onMessage(Session session, String socketPacket) throws IOException {
//do something else
}
...
}
The code to start the embedded server:
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import javax.websocket.server.ServerContainer;
//other imports
public static void main(String[] args) {
Server server = null;
try {
server = new Server(3081);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
ServerContainer serverContainer = WebSocketServerContainerInitializer.configureContext(context);
serverContainer.addEndpoint(WebsocketService.class);
server.setHandler(context);
server.start();
server.join();
} catch (Exception e) {
logger.error(e.getMessage());
} finally {
if (server != null) {
server.destroy();
}
}
}
The code above works perfectly for the case without dependency injection. However, I want to inject the dbProvider into my WebsocketService and use it in the onMessage method.
QUESTION 1: How to do the injection for the websocket server?
P.S. There are multiple examples of how dependency injection is done for REST endpoinds using ResourceConfig + AbstractBinder + ServletContainer, but I am not sure how it can be applied for the case with the websocket server.
QUESTION 2: How to add a simple resource endpoint to the same server (to serve javascript)?
Quite a few moving parts in this question.
First you have to setup Weld (the CDI implementation) to properly integrate it with your ServletContextHandler
Typically seen like this ...
ServletContextHandler context = new ServletContextHandler();
// Enable Weld + CDI
context.setInitParameter(
CdiServletContainerInitializer.CDI_INTEGRATION_ATTRIBUTE,
CdiDecoratingListener.MODE);
context.addBean(
new ServletContextHandler.Initializer(context,
new CdiServletContainerInitializer()));
context.addBean(
new ServletContextHandler.Initializer(context,
new org.jboss.weld.environment.servlet.EnhancedListener()));
Then the injection (actually decoration) is automatically taken care of internally between Jetty and Weld.
Note: the ServletContexthandler.Initializer is a convenience class to allow your embedded-jetty to run an arbitrary javax.servlet.ServletContainerInitializer without all of the overhead of a full blown WebApp and it's complex initialization process.
The CdiServletContainerInitializer is a ServletContainerInitializer that Jetty provides which sets up various things in the ServletContext to allow Weld to wire itself up properly to the ServletContext.
The EnhancedListener is also a ServletContainerInitializer that weld provides which does it's side of the wiring up for Weld + CDI.
For serving static files, you'll want to have a "Base Resource" defined in your ServletContextHandler and then add the DefaultServlet to the "default" url-pattern of "/".
ServletContextHandler context = new ServletContextHandler();
context.setBaseResource(Resource.newResource(webRootUri));
context.addServlet(DefaultServlet.class, "/");
If you want to see all of this together, check out the example project at
https://github.com/jetty-project/embedded-jetty-weld

EJB remote invoke lookup Weblogic - Liferay

I'm new with EJB and Im trying to consume a remote EJB from Liferay. EJB is deployed on WebLogic, Im using t3 client (wlthint3client.jar).
Part of the code of EJB is:
Stateless(name = "myDataEJB", mappedName = "ejb/MyDataEJB",
description = "Get important Data")
#Remote({
MyDataEJB.class,
SecurityContext.class
})
#RolesAllowed({
"MyRole"
})
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyDataEJBEJBImpl extends TheBaseSpringSecurityEJB implements MyDataEJBEJB {
//some stuff
And my code from Liferay is the next:
Properties p = new Properties();
p.put(Context.PROVIDER_URL, "t3://someip:someip,anotherip:anotherport");
p.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
p.put(Context.SECURITY_PRINCIPAL, "some");
p.put(Context.SECURITY_CREDENTIALS, "somepass");
try {
Context ctx = new InitialContext(p);
MyDataEJB mydataEJB =
(MyDataEJB)ctx.lookup("ejb/MyDataEJB#com.company.proyect.worker.ejb.MyDataEJB");
And I´m getting this:
javax.naming.NameNotFoundException: While trying to lookup 'ejb.MyDataEJB#com.company.proyect.worker.ejb.MyDataEJB' didn't find subcontext 'MyDataEJB#com'. Resolved 'ejb'[Root exception is javax.naming.NameNotFoundException:While trying to lookup 'ejb.MyDataEJB#com.company.proyect.worker.ejb.MyDataEJB' didn't find subcontext 'ejb.MyDataEJB#com.Resolved 'ejb'] remaining name 'ejb.MyDataEJB#com/company/proyect/worker/ejb/MyDataEJB''
Do you have any idea about what's happening?
Is the pattern ejb/MyDataEJB#com.company.proyect.worker.ejb.MyDataEJB for my lookup wrong?
Thank you so much! :)
try to use
MyDataEJB mydataEJB =
(MyDataEJB)ctx.lookup("ejb/MyDataEJB");
because your EJB is mapped by ejb/MyDataEJB in the JNDI.

Reference EJBs outside the Application server

I would like to know if any of you have ever call an EJB remotely. This is my scenario:
I have a single remote interface package in its own jar file. Then there is a EJB module (another jar file) that depends on the previous one to implement the interface as a #Stateless session bean.
I have deployed the EJB module in JBOSS 5.1.0.GA. When I try calling the EJB from within Eclipse, the returned object is not recognized as being of the interface type. Below are the differents java codes.
The Business interface:
#Remote
public interface RemoteBusinessInterface
{
public CustomerResponse getCustomerData( final CustomerRequest customerRequest );
}
Implementing class package in its own jar file:
#Stateless
public class RemoteEJBBean implements RemoteBusinessInterface
{
public CustomerResponse getCustomerData( final CustomerRequest customerRequest )
{...
And The code calling the remote EJB:
public class TestRemoteEjb
{
public static void main( final String[] args )
{
try
{
InitialContext initialContext = new InitialContext();
Object ref = initialContext.lookup( "java:/CustomerServiceBean/remote" );
System.out.println( ref );
if ( ref instanceof RemoteBusinessInterface )
{
System.out.println( "RemoteBusinessInterface" );
}
else
{
System.out.println( "Not of type RemoteBusinessInterface" );
}
}
catch ( NamingException e )
{
e.printStackTrace();
}
}
}
The output reads:
Reference Class Name: Proxy for: com.tchouaffe.remote.interfaces.RemoteBusinessInterface
Type: ProxyFactoryKey
Content: ProxyFactory/remote-ejb-1.0.0-SNAPSHOT/CustomerServiceBean/CustomerServiceBean/remote
Type: EJB Container Name
Content: jboss.j2ee:jar=remote-ejb-1.0.0-SNAPSHOT.jar,name=CustomerServiceBean,service=EJB3
Type: Proxy Factory is Local
Content: false
Type: Remote Business Interface
Content: com.tchouaffe.remote.interfaces.RemoteBusinessInterface
Type: Remoting Host URL
Content: socket://127.0.0.1:3873/
Not of type RemoteBusinessInterface
I have been wondering why the returned object is of a type other than RemoteBusinessInterface.
Thanks for any help.
Edmond
Try to check the following point:
It seems to be that you are not initializing the InitialContext object.
According to JBoss 5 documentation the properties needed are:
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,"org.jboss.naming.NamingContextFactory");
env.put(Context.URL_PKG_PREFIXES,"org.jboss.naming:org.jnp.interfaces");
env.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
InitialContext context = new InitialContext(env);
Additionaly, try to check if your client code has the necessary dependencies. The documentation is not clear enough about what are the jar files, but this link can help you to identify them. You also need to include the jar with the remote interface.

Export beans through HttpInvoker based on beans of certain interface

We have beans implementing a interface, lets say MyServicesInterface which we can autowire in java as a list using
#Autowired
List{MyServicesInterface} myServices;
I would like to do this in a application context using sudo code like below.
<beans>
<util:list id="servicesList" class="ArrayList" autowire-interface="com.MyServicesInterface" />
<for-each service:services>
<bean id="{/remote + service.getname}" class="org....HttpInvoker">
<property name="serviceInterface" class="{#service.getInterface()}"
</bean>
</for-each>
<beans>
This kind of dynamic for-each bean of type {Interface} create a exporter bean would be a great pattern for exporting beans. I know this can be done in java but having some difficulties create a HttpInvoker in java for each beans. I doubt this can be done completely in a application context but perhaps there is a approach i am overlooking.
Any comments or suggests would be great.
Use a BeanDefinitionRegistryPostProcessor to create the BeanDefinitions for your HttpInvokerServiceExporters. Use an annotation to mark the services and define the interface you want to export.
e.g
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
for (String name : registry.getBeanDefinitionNames()) {
try {
BeanDefinition definition = registry.getBeanDefinition(name);
String beanClassName = defintition.getBeanClassName();
cls = classLoader.loadClass(beanClassName);
if(cls.isAnnotationPresent(ExportableService.class)){
//Get annotation and pull out serviceInterface
GenericBeanDefinition beanDef = new GenericBeanDefinition();
beanDef.setBeanClass(HttpInvokerServiceExporter.class);
MutablePropertyValues values = new MutablePropertyValues();
values.addPropertyValue("service", new RuntimeBeanReference(name));
values.addPropertyValue("serviceInterface", "service interface from annotation>);
beanDef.setPropertyValues(values);
// Bean name here should be e.g. /myService so its picked up by the BeanNameUrlHandlerMapping (if you so desire)
registry.registerBeanDefinition(<beanName>, beanDef);
}
}
} catch(ClassNotFoundException e){
// Handle exception
}
}
I doubt U can do it with xml context, but With java it is simple.
So In java I would do like that:
List<MyServicesInterface> mylist = applicationContext.getBeansOfType(MyServicesInterface.class).values();
ServiceInterface si = applicationContext.getBean(ServiceInterface.class);
for(MyServicesInterface mi: mylist){
si.callSomething(mi);
}
That how I would it in java.

Embedded jetty ServletTester serving single static file

I'm unit testing with jetty and I want to serve not only my servlet under test but a static page as well. The static page is needed by my application. I'm initializing jetty like this
tester = new ServletTester();
tester.setContextPath("/context");
tester.addServlet(MyServlet.class, "/servlet/*");
tester.start();
What I need now, is something like
tester.addStaticPage("local/path/in/my/workspace", "/as/remote/file");
Is this possible with jetty?
I don't think you can do this with ServletTester. ServletTester creates a single Context for the servlet. You need to set up embedded jetty with at least two contexts: one for the servlet, and one for the static content.
If there was a full WebAppContext, you'd be set, but there isn't.
You could make a copy of ServletTester and add hair, or you can just read up on the API and configure the necessary contexts. Here's a code fragment to show you the basic idea, you will
not be able to compile this as-is. You will need to create a suitable context for the static content.
server = new Server();
int port = Integer.parseInt(portNumber);
if (connector == null) {
connector = createConnector(port);
}
server.addConnector(connector);
for (Webapp webapp : webapps) {
File sourceDirFile = new File(webapp.getWebappSourceDirectory());
WebAppContext wac = new WebAppContext(sourceDirFile.getCanonicalPath(), webapp.getContextPath());
WebAppClassLoader loader = new WebAppClassLoader(wac);
if (webapp.getLibDirectory() != null) {
Resource r = Resource.newResource(webapp.getLibDirectory());
loader.addJars(r);
}
if (webapp.getClasspathEntries() != null) {
for (String dir : webapp.getClasspathEntries()) {
loader.addClassPath(dir);
}
}
wac.setClassLoader(loader);
server.addHandler(wac);
}
server.start();
Set the resource base to the directory containing your static content, and add the jetty "default servlet" to serve that content. I have added the appropriate code to your example below.
tester = new ServletTester();
tester.setContextPath("/context");
tester.setResourceBase("/path/to/your/content");
tester.addServlet(MyServlet.class, "/servlet/*");
tester.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/*");
tester.start();

Categories

Resources