Quartz scheduled jobs could not access datasource in Websphere - datasource

I am developing a web app where batch programs need to run for specific times. I used Quartz library to schedule the jobs. The web app is deployed on Websphere 8.5.5 and its working fine, accessing the tables through datasources (Datasource given in code is java:comp/env/jdbc/db_datasource). The job is also triggered at the mentioned times.
I am getting an error when the scheduled job makes a DB connection through the datasource and the error is:
javax.naming.ConfigurationException: A JNDI operation on a "java:" name cannot be completed because the server runtime is not able to associate the operation's thread with any J2EE application component. This condition can occur when the JNDI client using the "java:" name is not executed on the thread of a server application request. Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application. Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on "java:" names. [Root exception is javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".]
at com.ibm.ws.naming.java.javaURLContextImpl.throwExceptionIfDefaultJavaNS(javaURLContextImpl.java:522)
at com.ibm.ws.naming.java.javaURLContextImpl.throwConfigurationExceptionWithDefaultJavaNS(javaURLContextImpl.java:552)
at com.ibm.ws.naming.java.javaURLContextImpl.lookupExt(javaURLContextImpl.java:481)
at com.ibm.ws.naming.java.javaURLContextRoot.lookupExt(javaURLContextRoot.java:485)
at com.ibm.ws.naming.java.javaURLContextRoot.lookup(javaURLContextRoot.java:370)
I understand from the error message is that the job is running outside the J2ee container and so the datasource is not available for the Job to make the connection, which I cannot agree as the Quartz is implemented as the ServletContextListener and the same is mentioned in web.xml.
Web.xml
<listener>
<listener-class>com.ehacampaign.helper.EHAJobSchedulerListener</listener-class>
</listener>
EHAJobSchedulerListener.java
public class EHAJobSchedulerListener implements ServletContextListener {..}
As you can see the code, the class is registered in the web and I do not understand why it cannot use the datasource in the J2EE container.
Questions are:
Why servlet registered class cannot access the datasource in J2EE
container?
If datasource in container cannot be used, then how to make a
connection to the DB while executing the job?
NOTE: I have the same setup in JBoss AS 7.1 and the jobs are running smoothly accessing the datasource configured in JBoss AS 7.1. I have to develop this in Websphere as the customer demands it.
UPDATED
I have attached the modified quartz property file. Even after adding the workmanagerthread, I am getting the same error.
org.quartz.threadPool.threadCount=1
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
org.quartz.threadExecutor.class=org.quartz.commonj.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default

In order to perform JNDI lookups in WebSpehre, your code must be running on a managed thread. In order to have Quartz run on one of WebSphere's managed threads, you must set the following 2 properties in your quartz.properties (as Alasdair mentioned in the comments):
org.quartz.threadExecutor.class=org.quartz.commonj.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default
The name for org.quartz.threadExecutor.workManagerName can be the JNDI name of any Work Manager that you have configured in WebSphere. I recommend simply using wm/default because it is in your configuration by default.

With all the help provided by aguibert and Alasdair and reference from here, I am able to fix the issue.
The Quartz property file is:
org.quartz.threadPool.threadCount=1
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
org.quartz.threadExecutor.class=org.quartz.commonj.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default
The database connection or JNDI lookup should happen within the empty constructor of the JOB Implemented class. For ex,
public class ContractIdFromPartyServiceJob implements Job {
private DataSource ds;
public ContractIdFromPartyServiceJob() {
try {
Logger.info("Gets the data source");
Context context = new InitialContext();
ds = (DataSource) context.lookup(ApplicationConstants.RESOURCE_REFERENCE_JDBC);
} catch (RException e) {
e.printStackTrace();
}
}
#Override
public void execute(JobExecutionContext arg0) throws JobExecutionException
{
EHAMarsDAO marsDao = new EHAMarsDAO();
Connection con = getConnection();
try {
marsDao.callDBMethod(con);
} finally {
con.close();
}
}
public Connection getConnection() throws RACVException
{
Connection con = null;
try {
con = ds.getConnection();
con.setAutoCommit(false);
con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
} catch (SQLException e) {
throw new RException(Constants.ERROR_CODE_002, Constants.E012_DB_CONNECTION_ERROR, e);
}
return con;
}
}

Related

How to catch error when message have been sent from JMS

I am sending an message through my standalone application that uses EJB MDB to communicate to my other application server that is running on JBOSS server.My application server is connected to a MSSQL server. In certain scenario, connection to the database is lost on application server side and we get following error -
Connection is reset.
Later , when i try to send message i don't get any error at my standalone EJB MDB logs and the process just stops executing.I get error log on application server side logs but same logs don't get propagated to my EJB MDB error logs.
As per my understanding, when db connection is lost all the ejb bean present in jboss container get nullified too.(I could be wrong here, i am new to EJB).
I tried implementing below code in my code that use to send message -
QueueConnection qcon = null;
#PostConstruct
public void initialize() {
System.out.println("In PostConstruct");
try {
qcon = qconFactory.createQueueConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
#PreDestroy
public void releaseResources() {
System.out.println("In PreDestroy");
try {
if(qcon != null)
{
qcon.close();
}
if(qcon== null){
throw new Exception(" new exception occured.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
I was in a impression that Queueconnection object will be nullified, when our db connection have been lost(as we are creating bean and making connection for message). But it doesn't seem to work.
I did found a way to call back my application after sending message. I used a separate temporary queue and used setJMSReplyTo method to set the reply destination. More info could be obtained from this
link. Hope this helps others.

Spring boot JNDI datasource lookup failure - Name comp/env/jdbc not found in context "java:"

I have setup a spring boot (v 1.1.9) application to deploy as a WAR file. And I'm trying to integrate this web application with an existing data service module (added as a maven dependency).
Environment trying to deploy: WebSphere Application Server 8.5.5.4
The issue I'm facing is an application start-up failure when try to look-up a JNDI dataSource (jdbc/fileUploadDS) as below within the dependent data service module.
#Configuration
#Profile("prod")
public class JndiDataConfig implements DataConfig {
#Bean
public DataSource dataSource() throws NamingException {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/fileUploadDS");
}
}
My Spring Boot configuration:
#Configuration
#ComponentScan(basePackages = { "au.com.aiaa.fileupload.data.*", "demo" })
#EnableAutoConfiguration(exclude = { HibernateJpaAutoConfiguration.class, DataSourceAutoConfiguration.class })
public class SampleApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(applicationClass, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<SampleApplication> applicationClass = SampleApplication.class;
#Bean
public static Properties fileUploadJndiProperties() throws NamingException {
JndiObjectFactoryBean jndiFactoryBean = new JndiObjectFactoryBean();
jndiFactoryBean.setJndiName("props/FileUploadProperties");
jndiFactoryBean.setExpectedType(Properties.class);
jndiFactoryBean.setLookupOnStartup(true);
jndiFactoryBean.afterPropertiesSet();
return (Properties) jndiFactoryBean.getObject();
}
}
Note that I'm able to lookup props/FileUploadProperties successfully. But failing to do the same for a datasource.
My doubt is it is trying to load a EmbeddedWebApplicationContext which is not what I want.
The stack trace is:
Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig.dataSource() throws javax.naming.NamingException] threw exception; nested exception is **javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".**
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:301)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1186)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at **org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)**
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:142)
at org.springframework.boot.context.web.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:89)
at org.springframework.boot.context.web.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:51)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
..................
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig.dataSource() throws javax.naming.NamingException] threw exception; nested exception is **javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".**
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:586)
... 132 common frames omitted
Caused by: javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".
at com.ibm.ws.naming.ipbase.NameSpace.getParentCtxInternal(NameSpace.java:1970)
at com.ibm.ws.naming.ipbase.NameSpace.retrieveBinding(NameSpace.java:1377)
at com.ibm.ws.naming.ipbase.NameSpace.lookupInternal(NameSpace.java:1220)
at com.ibm.ws.naming.ipbase.NameSpace.lookup(NameSpace.java:1142)
at com.ibm.ws.naming.urlbase.UrlContextImpl.lookupExt(UrlContextImpl.java:1436)
at com.ibm.ws.naming.java.javaURLContextImpl.lookupExt(javaURLContextImpl.java:477)
at com.ibm.ws.naming.java.javaURLContextRoot.lookupExt(javaURLContextRoot.java:485)
at com.ibm.ws.naming.java.javaURLContextRoot.lookup(javaURLContextRoot.java:370)
at org.apache.aries.jndi.DelegateContext.lookup(DelegateContext.java:161)
at javax.naming.InitialContext.lookup(InitialContext.java:436)
at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig.dataSource(JndiDataConfig.java:41)
at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig$$EnhancerBySpringCGLIB$$8001dbbe.CGLIB$dataSource$0(<generated>)
at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig$$EnhancerBySpringCGLIB$$8001dbbe$$FastClassBySpringCGLIB$$3c9e0518.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig$$EnhancerBySpringCGLIB$$8001dbbe.dataSource(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
What am I missing here? Even when I try to explicitly define the dataSource bean method in SampleApplication.java like below it fails with the same error.
#Bean
public static DataSource dataSource() throws NamingException {
JndiObjectFactoryBean jndiFactoryBean = new JndiObjectFactoryBean();
jndiFactoryBean.setJndiName("java:comp/env/jdbc/fileUploadDS");
jndiFactoryBean.setExpectedType(DataSource.class);
jndiFactoryBean.setLookupOnStartup(true);
jndiFactoryBean.setResourceRef(true);
jndiFactoryBean.afterPropertiesSet();
return (DataSource) jndiFactoryBean.getObject();
}
I referred this and it says we need to set enableNaming() on servlet container? Can I do something similar for non-embedded web application context? Or is it purely a WAS 8.5 issue??
You need to have resource reference with jdbc/fileUploadDS name in your web.xml. And make sure it is bound to actual datasource name during installation or via ibm-web-bnd.xml file.
Definition in web.xml:
<resource-ref>
<description />
<res-ref-name>jdbc/fileUploadDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
If you dont want to use web.xml, then in normal Java EE app you could just add in web component (servlet, filter) the following class annotation:
#Resource(name="jdbc/fileUploadDS", type=javax.sql.DataSource.class, lookup="jdbc/fileUploadDS")
but I'm not Spring-boot expert, so don't know, if it will work or is possible there.
I am able to connect my Spring-Boot application (deployed in Websphere Application Server 9) to WAS datasource.
The following code worked for me, for connecting to DataSource:
#Bean(name = "WASDataSource")
public DataSource WASDataSource() throws Exception {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource("DSNAME");
}
#Bean(name = "WASDataSourceJdbcTemplate")
public JdbcTemplate jdbcTemplate_WASDS(#Qualifier("WASDataSource")
DataSource dsDB2) {
return new JdbcTemplate(dsDB2);
}
Note: The name of Datasource "DSNAME" is the name which appears on the UI of Websphere console.
You can see that via -> Select Resources > JDBC > Data Sources.
Then I created jdbc template:
#Autowired
#Qualifier("WASDataSourceJdbcTemplate")
private JdbcTemplate db2WASTemplate;`
And running query using the query method works fine :
db2WASTemplate.query()
I did not create any Web.xml or ibm-web-bnd.xml files
I just configured spring boot with my custom datasource as follows:
#Bean
#ConfigurationProperties("spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
and inside the application.properties file I defined all datasource settings as usual
spring.datasource.driver-class-name= ***
spring.datasource.url= ***
spring.datasource.username= ***
spring.datasource.password= ***
spring.datasource.jndi-name=jdbc/myDB
It works nicely with #SpringBootApplication with all other default settings
I am facing the same problem. I don't know how to define tag in spring boot since there is no web.xml file in the spring boot.
So far what I came to know that we have to define it in the application file from where we start our spring application. I think we need to use this method to set the Datasource:
#Bean(destroyMethod="")
#ConfigurationProperties(prefix="datasource.mine")
public DataSource dataSource() throws Exception {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource("java:jdbc/configurationFile");
}

Sending Text Message using JMS on glassfish server

I am testing JMS with glassfish server so for that i want to send simple text message on glassfish server queue. I have tried with ActiveMQ and that is going fine but i unable to understand what can i put in configuration jndi.properties file and which jar is needed for glassfish server. Please give me some idea to implement this.
thanks in advance
Since you're using Glassfish, the easiest way is to write simple application (EJB) that will perform the task. You have to define in GF:
ConnectionFactory (Resources -> JMS Resources -> Connection Factory),
let's give it JNDI name jms/ConnectionFactory
Message queue (Resources -> JMS Resources -> Destination Resources),
let's give it JNDI name jms/myQueue
Next step is to use these in some EJB that you need to write. It's not hard: firstly, you have to inject:
#Resource(mappedName="jms/ConnectionFactory")
private ConnectionFactory cf;
#Resource(mappedName="jms/myQueue")
private Queue messageQueue;
and then use it like this:
..
javax.jms.Connection conn = null;
javax.jms.Session s = null;
javax.jms.MessageProducer mp = null
try {
conn = cf.createConnection();
s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
mp = s.createProducer(messageQueue);
javax.jms.TextMessage msg = s.createTextMessage();
msg.setStringProperty("your-key", "your-value");
msg.setText("Your text message");
mp.send(msg);
}
catch(JMSException ex) {
// exception handling
}
finally {
try {
// close Connection, Session and MessageProducer
} catch (JMSException ex) {
//exception handling
}
}
Regarding configuration, you don't need any external JAR, everything that is needed is shipped. If you don't want to write EJB, but regular Java (standalone) application, then you'll have to include jms.jar and imq.jar.

How do I force GlassFish 2 to load EJBs on startup?

We're using EJB3 on GlassFish v2.
My application includes a GenericServlet called StartupServlet, which has an init method. java.util.TimerTask pollers started from this method cannot lookup facades from the InitialContext.
However if I make an HTTP request and do a lookup, it succeeds. Therefore I have a workaround now where my poller startup code makes an HTTP connection to a page which looks up the interfaces they need.
How can I rearrange my application so I don't need to use such a hack? If possible the solution needs to work on GFv3 as well.
Thanks in advance for your help!
On GF 2, I have a servlet that on start ensures that my timer is created. This looks up a remote session bean and calls it successfully from the init() (not actual code, distilled down to the important parts):
#EJB(name="TimerSessionRef", beanInterface=TimerSessionRemote.class)
public class StartTimers extends HttpServlet {
#Override
public void init() throws ServletException {
super.init();
try {
Context ctx = new InitialContext();
TimerSessionRemote timerSession = (TimerSessionRemote) ctx.lookup("java:comp/env/TimerSessionRef");
timerSession.createTimer();
} catch (NamingException ex) {
logger.blah();
}

Problem Loading SSIS Custom Connection Manager/Type

I'm currently trying to build a custom connection manager and custom data flow source for a proprietary system at work, and I'm running into an odd problem when I attempt to execute a task containing my custom manager (from BIDS, DTEXEC, or the agent)
Error: 0xC0014005 at : The connection
type "AF" specified for connection
manager "AFConnection" is not
recognized as a valid connection
manager type. This error is returned
when an attempt is made to create a
connection manager for an unknown
connection type. Check the spelling in
the connection type name. Error:
0xC0010018 at : Error loading value
"<DTS:ConnectionManager
xmlns:DTS="www.microsoft.com/SqlServer/Dts"><DTS:Property
DTS:Name="DelayValidation">0</DTS:Property><DTS:Property
DTS:Name="ObjectName">AFConnection</DTS:Property><DTS:Property
DTS:Name="DTSID">{43304F2E-0C3F-4C00-9221-BD88C50EDDFC}"
from node "DTS:ConnectionManager".
I have the relevant DLLs in the GAC as well as the \90\DTS\Connections folder. All other connection managers work fine.
Here is the connection manager boilerplate:
[DtsConnection(ConnectionType="AF", Description="Connection manager for AF2", DisplayName="AF Connection"
, UITypeName = "AnalysisFrameworkCustomTask.AFConnectionManagerUI,AnalysisFrameworkCustomTask,Version=1.0.0.0,Culture=neutral,PublicKeyToken=e11db2e10378dc29")]
public class AFConnectionManager : ConnectionManagerBase
{
#region Overrides
public override DTSExecResult Validate(IDTSInfoEvents infoEvents)
{
// Code omitted that determines success or failure
return DTSExecResult.Success;
}
public override object AcquireConnection(object txn)
{
// Code ommitted to return new connection; works fine when debugged
// in the development environment
}
public override void ReleaseConnection(object connection)
{
// Code ommitted to release connection; works fine when debugged
// in the development environment
}
#endregion
}
Has anyone seen this before and have any idea how to move forward?
Try restarting the SSIS service.