Configuring Quartz job to call EJb with EJBInvokerJob - websphere

I need to call an ejb method from a quartz job an I'm having trouble with locating the ejb job. I have defined a Local interface and an stateless implementation. When deploying on websphere 7, the EjbInvokerJob is unable to find my component in my jndi tree.
This is my quartz job definition (this is loaded via the quartz init servlet)
JobDetail jd = JobBuilder//
.newJob(EJBInvokerJob.class)//
.withIdentity("job", "group")//
.usingJobData(EJBInvokerJob.EJB_JNDI_NAME_KEY, "ejb/myBean")//
.usingJobData(EJBInvokerJob.EJB_METHOD_KEY, "update")//
.build();
String cronExpr = getInitParameter("cronExpr");
Trigger cronTrigger = TriggerBuilder//
.newTrigger() //
.forJob(jd) //
.startNow() //
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpr))//
.build();
Scheduler sched = StdSchedulerFactory.getDefaultScheduler();
sched.scheduleJob(jd, cronTrigger);
sched.start();
And my bean has this annotation on top of it
#Stateless(name = "myBean")
How should I bind my EJB_JNDI_NAME_KEY? in websphere or should I be able to do this via this configuration. I think the problem is with my lack of jndi tree knowledge. Since the servlet which starts the job runs in the same jvm, so a local interface should be enough

Since portable global JNDI names (java:global namespace) were not available until Java EE 6, you should bind EJB into component's namespace (servlet in this case). Then lookup can be performed using java:comp/env/ejb/myBean name.
The following entry is required in web.xml:
<ejb-local-ref>
<ejb-ref-name>ejb/myBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>LOCAL_EJB_INTERFACE</local>
</ejb-local-ref>

Related

OpenLiberty NameNotFoundException: java:/comp/env

I have a web app running in Tomcat correctly that I want to run on the new OpenLiberty server, the app is starting correctly inside OpenLiberty but at the moment of the database connection initiation is throwing the following exception:
[Default Executor-thread-15] 2018-03-15 15:02:30 ERROR TomcatConnectionManager:41 - Loading jdbc/mysql/myaap failure
javax.naming.NameNotFoundException: java:/comp/env
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLName.<init>(JavaURLName.java:83)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLNameParser.parse(JavaURLNameParser.java:39)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLNameParser.parse(JavaURLNameParser.java:60)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext$NameUtil.<init>(JavaURLContext.java:474)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext.lookup(JavaURLContext.java:321)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext.lookup(JavaURLContext.java:370)
at org.apache.aries.jndi.DelegateContext.lookup(DelegateContext.java:161)
The above exception is thrown during the lookup phase:
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
Is there any way to make it work on OpenLiberty doing less changes possible?
On OpenLiberty the equivalent lookup would look like this:
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:comp/env");
The key is that you need to use java:comp/... instead of java:/comp/...
The reason why Tomcat is different than Liberty is because Tomcat is just a servlet container and Liberty conforms to the full Java EE specification.
According to section EE.5.2.2 of the Java EE 7 spec:
The application component’s naming environment is composed of four logical
namespaces, representing naming environments with different scopes. The four
namespaces are:
java:comp – Names in this namespace are per-component (for example, per enterprise
bean). Except for components in a web module, each component gets
its own java:comp namespace, not shared with any other component. Components
in a web module do not have their own private component namespace.
See note below.
java:module – Names in this namespace are shared by all components in a
module (for example, all enterprise beans in a single EJB module, or all components
in a web module).
java:app – Names in this namespace are shared by all components in all modules
in a single application, where “single application” means a single deployment
unit, such as a single ear file, a single module deployed standalone, etc.
For example, a war file and an EJB jar file in the same ear file would both have
access to resources in the java:app namespace.
java:global – Names in this namespace are shared by all applications deployed
in an application server instance. Note that an application server instance
may represent a single server, a cluster of servers, an administrative
domain containing many servers, or even more. The scope of an application
server instance is product-dependent, but it must be possible to deploy multiple
applications to a single application server instance.
Had a similar problem going between WebSphere and Tomcat. I'm developing and testing on a Tomcat server and using utilities I can't change that handle the DB connection to our DB2. On WebSphere it uses a constant set to "jdbc/COMPDB2" to retrieve the DataSource when I configure Tomcat and my Web.xml file it resolves to "java:comp/env/jdbc/SFCCDB2"
My work around for on local work space it to add a listener to copy the resource to the level in the InitialContext. I'm not very experienced with the server side of things but this is working so far using TomEE 7.0.81.
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/SFCCDB2");
javax.naming.Context envCtx = (javax.naming.Context) ctx.lookup("java:comp/env");
try{
/*
Added this because after redeploying code to the server it would error
connecting to the DB with an SQLException Datasource is closed
*/
DataSource dataSource = (DataSource) ctx.lookup("jdbc/COMPDB2");
ctx.destroySubcontext("jdbc");
} catch (NamingException e){
//Doesn't exist; safe to just add
}
ctx.createSubcontext("jdbc");
ctx.bind("jdbc/COMPDB2", ds);
ctx.close();

Spring JMS running as a JAR project

I have a Spring JMS application. Infact there is no UI. Just Spring configuration (JMS listener) and the Spring configuration is loaded by web.xml .
so when i deploy in server, the listener starts working.
But I do not want the web part, because, there no UI, It is just a project which listen to a Queue and do its processing. So I think it should be JAR and it should run standalone(or when i deploy in server) How to create such project/ JAR when deployed in server it automatically starts running. I do not want run a main class every time I update the JAR.
I have used an executable jar to launch a JMS queue before. You just have to make sure you have access to all the jar dependencies for Spring and JMS, which is a lot. This can be done by setting the classpath to point at the dependency jars or create an Uberjar and pack all the dependency jars in the executable jar.
Here is an example class that will start up ActiveMQ from a Jar when you set it as a the main-class in the jar manifest. A jms.pid will be created with the process id for process. You must set the paths to your Spring contexts for JMS in the ConfigurableApplicationContext.
public class Server {
public static void main(String[] args) throws Exception {
// Define Spring contexts required for JMS to run
List<String> contexts = Arrays.asList( "classpath:applicationContext.xml", "classpath:spring/jmsContext.xml" );
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext(contexts);
// Get activeMQ from JMS context
BrokerService broker = applicationContext.getBean( "broker" );
// Start up activeMQ
broker.start();
// Get pid for this process
String sysId = ManagementFactory.getRuntimeMXBean().getName();
String pid = sysId.substring(0, sysId.indexOf("#"));
// Write PID file
File file = new File("jms.pid");
DataOutputStream outs = new DataOutputStream(new FileOutputStream(file, false));
outs.write(pid.getBytes());
outs.close();
}
}
Example Spring configuration for getting access to the BrokerService
<bean id="broker" class="org.apache.activemq.xbean.BrokerFactoryBean">
<property name="config" value="classpath:org/activemq/xbean/activemq.xml" />
<property name="start" value="true" />
</bean>
I have typically seen JMS applications run as Windows Services or Unix daemons. These provide you features that you can configure like restarting your JMS app if the server reboots, etc.
There are some commercial Java EE containers like Weblogic that provide start-up classes that you can use to start your JMS application when a node in the cluster starts. This provides console control over the JMS application / server. It doesn't sound like that is an option in your case though.

How to unregister an OSGI/Blueprint Service from within the Service?

In my application I have a Service ChatProtocolClient. The implementation is a tcp client which connects to a remote server in the blueprint "init-method" and disconnects in the "destroy-method".
I also have another bundle that uses this ChatProtocolClient's connection to read and post messages from a channel, ChatChannel.
Currently I have an xml file that creates a bean of the ChatProtocolClient, and creates a bean ChatChannel in which a reference to the created ChatProtocolClient service is injected.
But how can I handle disconnects from the server? I'd want to tell the Blueprint framework that my ChatProtocolClient instance is unusable now and it should unregister this instance.
Preferably Blueprint would then automatically call the destroy-method on all dependent beans (beans in which Blueprint injected this service reference) and initialize a new ChatProtocolClient bean and all beans that were destroyed because the dependency failed.
How can this be done?
I found a way to implement this. In this solutions it's not Blueprint that recreates instances of all dependent services. It goes like this:
Connection "Watchdog" beans.
Instead of creating "ChatProtocolClient" Beans, I created ConnectionWatchDog beans from xml. In these beans the BundleContext is injected and the connection properties are set from the .xml file.
The ConnectionWatchDog then tries to create/connect a ChatProtocolClient instance. If connection succeeds, it registers a service in the BundleContext (with bundleContext.registerService(..)). The ServiceRegistration is kept in the watchdog. The watchdog tests the connection on set interval (it runs it's own Thread). If the connection appears to have failed; the watchdog calls the serviceRegistration.unregister() and cleans up the remainders of the client connection instance, ands starts the whole proces of creating, connecting and registering an new ChatProtocolClient instance.
The ChatChannel
The ChatChannel is now configured in Blueprint with a . The xml looks like this:
<blueprint xmlns=...>
<reference-list id="chat-connection" member-type="service-object" interface="com.example.ChatProtocolClientInterface">
<reference-listener bind-method="onBind" unbind-method="onUnbind" ref="Channel1"/>
</reference-list>
<bean id="Channel1" class="ChatChannel" init-method="startUp">
<property name="chatProtocolClient" ref="chat-connection">
... some other properties ...
</bean>
</blueprint>
The member-type set to service-object, means that when a service is registered or unregistered, the ChatChannel will be informed with the "onBind" and "onUnbind" methods. As parameter, they'll get a ChatProtocolClientInterface instance.
I'm not sure whether this is the only or best solution, but it works for me. Note that with this example xml, you'll also need a setter for "chatProtocolClient"; currently I don't use the list that is set by blueprint and I only use the onBind and onUnbind methods.

How to delay spring beans startup?

Having spring application (actually grails app) that runs apache-activemq server as spring bean and couple of apache-camel routes. Application use hibernate to work with database. The problem is simple. Activemq+Camel starts up BEFORE grails injects special methods into hibernate domain objects (actually save/update methods etc). So, if activemq already has some data on startup - camel starts processing messages w/o having grails DAO methods injected. This fails with grails.lang.MissingMethodException. Must delay activemq/camel startup before Grails injects special methods into domain objects.
If all these are defined as spring bean, you can use
<bean id="activeMqBean" depends-on="anotherBean" />
This will make sure anotherBean is initialized before activeMqBean
can you move MQ managment into a plugin? It would increase modularity and if you declare in plugin-descriptor
def loadAfter = ['hibernate']
you should have the desired behavior. Works for JBPM plugin
I am not sure in your case but lazy loading may also help e.g.
<bean id="lazybean" class="com.xxx.YourBean" lazy-init="true">
A lazily-initialized bean indicates to the IoC container to create bean instance when it is first requested. This can help you delay the loading of beans you want.
I know this question is pretty old, but I am now facing the same problem in the year 2015 - and this thread does not offer a solution for me.
I came up with a custom processor bean having a CountDownLatch, which I count down after bootstrapping the application. So the messages will be idled until the app has started fully and its working for me.
/**
* bootstrap latch processor
*/
#Log4j
class BootstrapLatchProcessor implements Processor {
private final CountDownLatch latch = new CountDownLatch(1)
#Override
void process(Exchange exchange) throws Exception {
if(latch.count > 0){
log.info "waiting for bootstrapped # ${exchange.fromEndpoint}"
latch.await()
}
exchange.out = exchange.in
}
/**
* mark the application as bootstrapped
*/
public void setBootstrapped(){
latch.countDown()
}
}
Then use it as a bean in your application and call the method setBootstrapped in your Bootstrap.groovy
Then in your RouteBuilder you put the processor between your endpoint and destination for all routes you expect messages coming in before the app has started:
from("activemq:a.in ").processRef('bootstrapProcessor').to("bean:handlerService?method=handle")

Using Spring to Access an EJB Across Clusters in WebSphere using Grails

I have spent the last few days attempting to integrate a Grails (version 1.3.2) application with an EJB 2.1 application that is deployed on WebSphere 6.1. Once our grails apps are in production, they will be deployed to WebSphere as well. The EJB 2.1 application is widely used across our company and, in anything except a local development environment, is deployed to its own cluster. The way we handle this in our existing Java EE applications (all of which are non-Spring, non-Grails) is to bind a CORBA CosNaming Naming Context within each of our other clusters that can then be used to obtain references to our shared EJB 2.1 application. So, up to this point, if one of our application needed to interact with this application, they would do so using an approach like this:
String cosNameBinding = "ejbApp.HighAvail.cluster";
InitialContext initial = new InitialContext();
Context fedContext = (javax.naming.Context) initialCtx.lookup(cosNameBinding);
Then do the normal EJB-style lookup/narrow/invoke using the federated/CosNaming context:
Object ejbHomeAsObject = fedContext.lookup(jndiNameOfService);
EJBHome home = (EJBHome) PortableRemoteObject.narrow(ejbHomeAsObject, homeClass);
Object service = invokeMethod(homeClass, home, "create");
As you can see, there is a level of indirection that occurs here in order to go from the InitialContext to the federated naming Context that can be used to interact with the shared EJB application.
Running locally, I have both the Grails application and the EJB application deployed to the same server (non network deployment WAS, same profile&node). I have Spring configured like so:
beans = {
ejbJndi(org.springframework.jndi.JndiTemplate) {
environment = ["java.naming.factory.initial" :
"com.ibm.websphere.naming.WsnInitialContextFactory"]
}
crewMemberService(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
jndiName="hotelService/ejb/HotelService"
businessInterface="com.company.appName.hotel.HotelService"
lookupHomeOnStartup="false"
cacheHome="false"
refreshHomeOnConnectFailure="true"
jndiTemplate = ref("ejbJndi")
}
}
And I can successfully inject ejb references into my Grails controllers and invoke them. However, WebSphere can only resolve the JNDI lookup because they are both deployed on the same server. When we move it to one of our development environments, we'll need jndi lookups for these services to go against the federated naming context.
So my questions are:
Is there a way to do this with the classes that are provided within Spring and if so could you give me an idea of how I would need up modify my Spring config to do so?
Given that there is no flexibility around how we deploy the other app or gain references to its services (we must use the federated context), should I consider extending JndiTemplate and do the necessary wiring myself?
If anyone has faced this situation I would be most appreciative for any insights you may be able to offer.
In case anyone has this same question down the road, I ended up implementing an extension to Spring's JndiTemplate and using that. Here is the code:
public class FederatedJndiTemplate extends org.springframework.jndi.JndiTemplate
{
protected static final String JNDI_CONTEXT_BINDING_NAME = "fed.context.jndiName";
/**
* Obtain a JNDI naming context for the specified federated naming context.
*
* #throws NamingException if no "fed.context.jndiName" has been specified in
* the environment properties for the jndiTemplate or the container throws a naming
* exception.
*/
#Override
protected Context createInitialContext() throws NamingException {
Properties props = super.getEnvironment();
if(!props.containsKey(JNDI_CONTEXT_BINDING_NAME)) {
throw new NamingException("You must specify the federated naming context JNDI binding name");
}
String jndiBinding = props.getProperty(JNDI_CONTEXT_BINDING_NAME);
InitialContext initCtx = new InitialContext();
Context fedCtx = (Context) initCtx.lookup(jndiBinding);
return fedCtx;
}
}
Then inside my resources.groovy, I just used this JndiTemplate:
ejbJndi(com.myCompany.spring.jndi.FederatedJndiTemplate) {
environment = [
"fed.context.jndiName":"myServices.HighAvail.Cluster"]
}
hotelService(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
jndiName="hotelService/ejb/HotelService"
businessInterface="com.mycompany.appName.hotel.HotelService"
homeInterface="com.mycompany.appName.hotel.HotelServiceHome"
lookupHomeOnStartup="false"
jndiTemplate = ref("ejbJndi")
}

Resources