How to configure Java Message Driven Beans and Websphere Activation specification without hardcoded JNDI Names? - ejb

We have a MDB listening to a Queue reading data and sending data to another Queue
#MessageDriven(
activationConfig = { #ActivationConfigProperty(
propertyName = "destinationType", propertyValue = "javax.jms.Queue"
) },
mappedName = "jms/dataQ")
public class DataMDB implements MessageListener {
#Resource(name="jms/dataQueueConnectionFactory")
private ConnectionFactory connectionfactory;
#Resource(name="jms/dataDestinationQ")
private Destination destination;
...
}
and an XML (ibm-ejb-jar-bnd.xml) with bean configuration
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar-bnd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://websphere.ibm.com/xml/ns/javaee"
xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-ejb-jar-bnd_1_0.xsd"
version="1.0">
<message-driven name="DataMDB">
<jca-adapter activation-spec-binding-name="eis/dataListenerMDB"
destination-binding-name="jms/dataQ" />
<resource-ref name="jms/dataQueueConnectionFactory"
binding-name="jms/dataQueueConnectionFactory" />
<resource-env-ref name="jms/dataDestinationQ"
binding-name="jms/dataDestinationQ" />
</message-driven>
</ejb-jar-bnd>
and Activation specification for this MDB on WebSphere
As I have seen the examples over Google, this is the typical example of MDB and WAS Activation setup.
We have a problem here as all the JNDI names seen here are hardcoded in Java code anotations as well as in the ibm-ejb-jar-bnd.xml file.
So is there a way that these JNDI names can be brought outside the EJB project, so we could build one project for all customers and customers are free to have their Standard JNDI Names.
Else we have to build different .ear for each customer and which is not ideal.
Thanks in advance people.
Any ideas are welcome.

All values defined in the ibm-ejb-jar-bnd.xml maps references to the actual JNDI names. This can be overridden for each of your customers during application installation (mapping references to JNDI names steps in the admin console), after application installation, or during installation using scripts.
The binding file (ibm-ejb-jar-bnd.xml) provides only 'default names', in case you dont want to change them during installation.

Related

lookup to EJBHome from Outside the container via Standalone applicatiion failed

I have an EJB application which is Deployed in WebSphere 8
I am trying to connect it from Standalone java program following way
public static void main (String[] args) throws Exception
{
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
props.put(javax.naming.Context.PROVIDER_URL, "iiop//localhost:2809");
Context ctx = new InitialContext(props);
Object o = ctx.lookup("MyAppHome");
}
But this is leading to below exception
javax.naming.NameNotFoundException: Name "MyAppHome" not found in context
"serverlocal:CELLROOT/SERVERROOT".
at com.ibm.ws.naming.ipbase.NameSpace.lookupInternal(NameSpace.java:1228)
Further looking into it I found following supporting link https://www.ibm.com/developerworks/community/forums/html/threadTopic?id=ac01caaf-d2aa-4f3f-93b3-6f3d4dec3e6b
Here the answerer suggested using fully qualified bean name
java:global/ProjectName/ModuleName/BeanName!FullyQualif‌​iedNameOfRemoteInterface or BeanName#FullyQualif‌​iedNameOfRemoteInterface.
If it's a correct fix. Where can I find the Project name, Module Name and Bean Name? I do have xmi files in the project. Thanks!
The easiest way to determine the JNDI name for an EJB in WebSphere is to look for the binding information in the server logs. The JNDI names associated with each EJB interface are logged using the message ID CNTR0167I. Fore example:
CNTR0167I: The server is binding the com.example.DatabaseBean interface of the DatabaseBean enterprise bean in the TestProject.war module of the TestProject application. The binding location is: java:global/TestProject/DatabaseBean!com.example.DatabaseBean
Notice in this example that there does not appear to be both a project name (i.e. application name) and module name, because this test project was a standalone WAR module with an EJB packaged in it. Project/Application name is only used for EAR files.
Also note that a CNTR0167I is logged for JNDI names in both the java:global and SERVERROOT name contexts. So, in the error scenario above, it could be that the EJB was bound to ejb/MyAppHome and not just MyAppHome, so you can also determine the correct SERVERROOT JNDI name from the CNTR0167I messages as well. Either JNDI name may be used to lookup an EJB.

Multiple names for same EJB

Can I deploy an EJB under multiple names in a similar way as this is possible in Spring using a name alias?
According to EJB 3.0 specification:
At declaration time:
name
The annotation element name defines the bean “name” and defaults to the unqualified name of the bean class. The bean name must be unique in the scope of the module containing the EJB.
Referencing a EJB:
beanName
The beanName element specifies the bean “name” as declared in the #Stateful and #Stateless annotations via the name element or in the deployment descriptor via the element. The beanName element is most useful when more than one EJB implement the same business interface in an application: the beanName lets the developer reference a specific EJB in a specific module.
So, yes you could but the ejb must be packaged in different modules and then point it through the beanName.
Not As Spring., there could be ways but that is vendor specific, NOT PORTABLE.
Yes, it is possible to deploy same EJB under multiple names or aliases using ejb-jar.xml descriptor.
Moreover both name defined in the EJB xml descriptor and one defined in the annotation will be taken into account (although I would not risk mixing between xml descriptor and annotations in this case for portability reasons).
This example works on JBoss AS 7.1.1.Final:
#Local
public interface PingWorker {
String ping(String name);
}
#Stateless(name = "PingAlias") // first name
public class PingWorkerBean implements PingWorker {
#Override
public String ping(String name) {
return "Hello " + name;
}
}
<ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:ejb="http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd" version="3.0">
<enterprise-beans>
<session>
<ejb-name>PingWorker</ejb-name> <!-- second name -->
<ejb-class>com.xyz.service.PingWorkerBean</ejb-class>
<session-type>Stateless</session-type>
</session>
<session>
<ejb-name>PingProcessor</ejb-name> <!-- third name -->
<ejb-class>com.xyz.service.PingWorkerBean</ejb-class>
<session-type>Stateless</session-type>
</session>
</enterprise-beans>
</ejb-jar>
In referencing component you can declare:
#Stateless
public class PingBean implements Ping {
#EJB(beanName = "PingAlias")
private PingWorker pingWorkerByAnnotaion;
#EJB(beanName = "PingWorker")
private PingWorker pingWorkerByDescriptorOne;
#EJB(beanName = "PingProcessor")
private PingWorker pingWorkerByDescriptorTwo;
}
and all three references should be satisfied. On deployment there are three EJBs deployed which expose the same interface and implementation but with different names:
java:global/ear-app-1/ejb-1/PingProcessor!com.xyz.service.PingWorker
java:app/ejb-1/PingProcessor!com.xyz.service.PingWorker
java:module/PingProcessor!com.xyz.service.PingWorker
java:global/ear-app-1/ejb-1/PingProcessor
java:app/ejb-1/PingProcessor
java:module/PingProcessor
java:global/ear-app-1/ejb-1/PingAlias!com.xyz.service.PingWorker
java:app/ejb-1/PingAlias!com.xyz.service.PingWorker
java:module/PingAlias!com.xyz.service.PingWorker
java:global/ear-app-1/ejb-1/PingAlias
java:app/ejb-1/PingAlias
java:module/PingAlias
java:global/ear-app-1/ejb-1/PingWorker!com.xyz.service.PingWorker
java:app/ejb-1/PingWorker!com.xyz.service.PingWorker
java:module/PingWorker!com.xyz.service.PingWorker
java:global/ear-app-1/ejb-1/PingWorker
java:app/ejb-1/PingWorker
java:module/PingWorker
As you may see this works differently than aliases in Spring. While in Spring aliases are only different names that refer to the same instance or set of instances (depends on the scope) - in EJB you need to declare EJBs multiple times. In the EJB container these become separate EJBs in terms of instance pools etc.
Depending on what you are trying to achieve - you may also consider overriding referenced EJB name in referencing EJB (override annotation beanName with descriptor <ejb-link/>). More on this here:
Choose EJB to be injected without recompiling.

Collaboration from PlayN client with server

I have written a game in PlayN, which has to communicate with a JavaEE-Server with Seam.
First of all I only need the game running in HTML5.
The current issue is the communication between the PlayN-client and the JavaEE-Server
1) First I tried to communicate over the PlayN.net() interface exchanging information using JSON. Since PlayN is running on port 8888 and the server on 8080 I correctly run into problems with the same-origin-policy.
2) Now I'm looking for a working solution. Which one would you recommend? Do you have other ideas?
a) I'm trying to work with RPC as described in How to handle RPCs in client-server PlayN game?
, using GWT-syncproxy.
b) I try that playN runs on the same port as the server i.e. 8080 - so I don't have problems with the same-origin-policy any more. Question: Can the HTML5 playN app run on the same port?
So when I start the JavaEE-Server using Eclipse it should also start the PlayN web application, both on port 8080, right?
Is this possible?
c) The most hacky solution (currently working): The server writes the JSON-String into a file and the playN client reads this file out.
What do you recommend? I'd like to implement solution 2, since it is the cleanest solution, but I don't know how hard it is and how it works.
Thanks for your help!
I think the problem is that you are "running" PlayN, separated from your Seam server.
If I understood you correctly, you execute the Maven task to run your game as HTML and on the other hand you run Jboss (or whatever Java EE server), what you should do is run
mvn package
which will create the war of the game, and then publish that war on your Java EE server, then you can use the PlayN.net package with no problems whatsoever, running in a single server
This is how we currently handle our client / server communication. We are using a stateless JavaEE architecture and provide everything as REST services. This allows us to scale horizontally by adding more servers and simply adding them to the cluster entry in the Glassfish config.
However due to missing reflection or a working JSON lib, it forces us to implement a toJson()method in every data transfer object BY HAND (be carfull with case sensitivity). We added our server project as a module to the PlayN metaproject and added the core as a dependency to the server. So you can place every DTO on the core project (which is quite awesome). Placing them on the server results in people trying to annotate the classes as entities, which will result in failure during the html build. I am currently thinking about adding a shared project to the build, like in GWT projects.
This is how we send data to the server (for this example without any abstraction, do yourself a favor and implement one):
private void loadMapFromServer() {
SessionDto session = this.main.getSessionCtrl().getSessionMdl();
PlayN.net().post("http://localhost:8080/server/rest/map/mapMdl",
session.toJson(),
new Callback<String>() {
#Override
public void onSuccess(String result) {
mapMdl = new MapDto();
}
#Override
public void onFailure(Throwable cause) {
PlayN.log().error("fail " + cause.getMessage());
}
});
}
Notice how we bastardize the POST argument with session.toJson(). This is because of the missing MIME type feature and passing JSON strings via GWT will fail.
And this is how it looks on the server:
package com.fact.server;
//I also posted the imports, for clarity.
import com.fact.core.map.MapDto;
import com.fact.core.user.SessionDto;
import com.fact.server.game.map.MapCtrl;
import com.google.gson.Gson;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.log4j.Logger;
#Stateless
#Path("/map")
public class MapSrvs {
#Inject
Logger logger;
#Inject
MapCtrl mapCtrl;
Gson gson = new Gson();
#POST
#Path("/mapMdl/")
#Produces( MediaType.APPLICATION_JSON )
public MapDto getMapMdl(String sessionDtoStr) {
//logger.info("map was requested: " + sessionDtoStr);
// Use gson to deserialize the class. Jersey would do this, if PlayN
// would allow to set a correct MIME type (and #Consumes was set).
// We could simply write: getMapMdl(SessionDto sessionDto)
SessionDto sessionDto = gson.fromJson(sessionDtoStr, SessionDto.class);
if(sessionDto == null) {
return null;
}
// [...] check for a valid session
MapDto mapMdl = new MapDto();
mapMdl.foo = "message from server";
return mapMdl;
}
}
This would be a bit nicer, if PlayN would allow you to set the MIME type, so that you won't have to cast the String using Gson. However this works quite well. We use Jersey on the server side to handle all the REST stuff. To get it running I had to put the following into the web.xml:
<servlet>
<!-- We need jersey for the REST stuff -->
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.fact.server</param-value>
</init-param>
<init-param>
<!-- This took me hours to find :(. It is needed to automatically
map POJOs to JSON code. -->
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Also Jersey is already included into the Java-EE-Api, so it works out of the box. I hope this helps. If anyone knows how to do client side JSON parsing , please look at this question: How do I convert a POJO to JSON in PlayN?

Using Blazeds To Connect to a EJB on Glassfish

The task is to try to connect directly to a stateless EJB deployed on Glassfish. I have already done this via Web Service and I can also connect to the EJB by calling a remote java object which uses JNDI to find and load the bean. What I cannot do is directly connect to the EJB with Blazeds. I am using EBJ3Factory BY Ryan Norris (downloaded from adobe site) as follows;
My WEB-INF/flex/services-config.xml has;
<factories>
<factory id="ejb3" class="com.adobe.ac.ejb.EJB3Factory" />
</factories>
My WEB-INF/flex/remoting-config.xml has;
<destination id="MyEJB">
<properties>
<factory>ejb3</factory>
<source>java:global/Together/PSearch!ejb.PSearch</source>
</properties>
</destination>
I have a simple java class that can access the bean so I can use Blazeds to call the class which then calls the bean;
public void getBean() {
PSearch search;
InitialContext ctx;
try {
ctx = new InitialContext();
search = (PSearch) ctx.lookup("java:global/Together/PSearch!ejb.PSearch");
System.out.println("jndi okay");
} catch (NamingException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
}
The asadmin command for the context in glassfish shows me;
./asadmin list-jndi-entries --context java:global/Together
PSearch__3_x_Internal_RemoteBusinessHome__: javax.naming.Reference
PSearch!ejb.PSearchRemote: javax.naming.Reference
PSearch!ejb.PSearch: com.sun.ejb.containers.JavaGlobalJndiNamingObjectProxy
PSearch!ejb.PSearchLocal: com.sun.ejb.containers.JavaGlobalJndiNamingObjectProxy
Yet when I use Eclipse / Flash Builder to try to Import a BlazeDS service I get an introspection error;
java:global/Together/PSearch/!ejb.PSearch is not available in the specified location
I have also tried changing the remoting-config.xml to point to local and remote interfaces but no joy!
Any pointers would be greatly appreciated.
One workaround you could do would be to remove the factory XML element, replace the source JNDI name with the EJB fully qualified class name and create the service with Flash Builder using the BlazeDS RTS service as you tried to do.
<destination id="MyEJB">
<properties>
<source>packagename.EJBClassName</source>
</properties>
</destination>
When you are done making the service client, service and the value objects(return type etc) in your Flex project then put everything back as they were:
<destination id="MyEJB">
<properties>
<factory>ejb3</factory>
<source>java:global/Together/PSearch!ejb.PSearch</source>
</properties>
</destination>
What u r going to do actually is to treat the EJB 3.x as a normal POJO for the introspection in order to create the AS3 classes and when u r done change the destination to an EJB3 destination by using the factory.
I am working on a way to make this steps unnecessary. If I have time to finish it I will let you know.

Using Freemarker with Restlet 2.0 in a Java EE server

I'm a bit confused with what is written in the documentation(s) for Freemarker and Restlet's freemarker extension.
Here's the situation: The restlet engine serves an HTML representation of a resource (e.g. www.mysite.com/{user}/updates). The resource returned for this URI is an HTML page containing all the updates, that is created with a freemarker template. This application is hosted on a Glassfish v3 server
Question(s):
The freemarker configuration should only be loaded once as per the freemarker documentation:
/* You should do this ONLY ONCE in the whole application life-cycle:Create and adjust the configuration */
Configuration cfg = new Configuration();
cfg.setDirectoryForTemplateLoading(
new File("/where/you/store/templates"));
cfg.setObjectWrapper(new DefaultObjectWrapper());
What is the best place to do this in a Java EE app? I am thinking of having it as context-param in web.xml and using a ServletContextListener - but I'm not sure how to go about doing that.
As per freemarker's documentation we could also add a freemarkerservlet and map .ftl url-patterns to it. But this is already mapped by a Restlet servlet (i.e., the url-pattern of "/"). So having another one for *.ftl doesn't make sense (or does it?)
So the question is basically about how best to integrate with the 'configuration' of Freemarker so that it happens only once and what is the 'entry-point' for that piece of code (who calls it). Has anyone successfully used Freemarker + restlet in a Java EE environment? Any ideas?
Thanks!
This was a tricky question - indeed. Required me to go through the implementation of the source files in org.restlet.ext.Freemarker package - Phew!
Here's how you can do it
If you need to create your OWN Configuration Object, set the 'templateLoader' to use and then have TemplateRepresentation 'work' on it for rendering:
Configuration cfg = new Configuration();
ContextTemplateLoader loader = new ContextTemplateLoader(getContext(),"war:///WEB-INF");
cfg.setTemplateLoader(loader);
TemplateRepresentation rep = null;
Mail mail = new Mail(); //The data object you wish to populate - example from Restlet itself
mail.setStatus("received");
mail.setSubject("Message to self");
mail.setContent("Doh!");
mail.setAccountRef(new Reference(getReference(), "..").getTargetRef()
.toString());
Map<String, Object> data = new HashMap<String, Object>();
data.put("status", mail.getStatus());
data.put("subject", mail.getSubject());
data.put("content", mail.getContent());
data.put("accountRef", mail.getAccountRef());
rep = new TemplateRepresentation("Mail.ftl", cfg, data, MediaType.TEXT_HTML);
return rep;
If you are happy with the default and wish to use a class loader based way of loading the templates
//Load the FreeMarker template
Representation mailFtl = new ClientResource(
LocalReference.createClapReference(getClass().getPackage())
+ "/Mail.ftl").get();
//Wraps the bean with a FreeMarker representation
return new TemplateRepresentation(mailFtl, mail, MediaType.TEXT_HTML);
If you want to initialize the Configuration Object once and set the template by calling the setServletContextForTemplateLoading(...) method on the configuration object. You could always do this in a ServletContextListener
public class Config implements ServletContextListener {
private static Configuration cfg = new Configuration();
#Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext sc = sce.getServletContext();
cfg.setServletContextForTemplateLoading(sc, "/WEB-INF");
}
public static Configuration getFMConfig()
{
return cfg;
}
}
And then call the static getFMConfig() and pass it to TemplateRepresentation as in 1
Things to note:
If you do get a protocol not supported Exception it'll be in case 2. Implies that the ServerResource doesn't know what protocol to use to access the file - It'll be the CLAP protocol of Restlet. You may have to set up the init-params for RestletServlet in the web.xml file and have CLAP as one of the param-values
The TemplateRepresentation has quite a few constructors - if you DON'T pass in a configuration object during instantiation (using another overloaded constructor), it will create a new Configuration() for you. So you don't have to do any configuration set up as in 2 (This may strike you as obvious but I assumed that you WOULD still need to set a configuration or it would 'pick it up from somewhere')
If you DO wish to have your OWN configuration setup you MUST pass it to one of the constructors
Have a look at the "war:///" string in the constructor of ContextTemplateLoader in 1. this is important No where is it mentioned what this baseUri reference should be, not even in the docs. I tried for quite a while before figuring it out that it should be "war:///" followed by the folder name where the templates are stored.
For case 2 you'll probably have to store the templates in the same package as the class file from where this code is accessed. If you see carefully you'll notice a LocalReference parameter as an argument to ClientResource saying that the resource is supposed to be locally present and thus you need to use the custom CLAP protocol (classLoader Access Protocol)
Personal Frustration point - why isn't all this even clarified in the documentation or ANYWHERE :)
Hope it helps someone who stumbles upon this post! Phew!

Resources