2016-06-17 1 views
1

Я разрабатываю веб-приложение, в котором пакетные программы должны запускаться в определенное время. Я использовал библиотеку Quartz для планирования заданий. Веб-приложение развернуто на Websphere 8.5.5 и его работоспособность, доступ к таблицам через источники данных (источник данных, заданный в коде, - java: comp/env/jdbc/db_datasource). Работа также срабатывает в указанное время.Запрошенные задания на квартет не могут получить доступ к источнику данных в Websphere

Я получаю сообщение об ошибке, когда запланированное задание устанавливает соединение DB через источник данных и ошибка:

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) 

я понял из сообщения об ошибке, что работа выполняется за пределами контейнера J2ee и так источник данных недоступен для задания для соединения, которое я не могу согласиться с тем, что кварц реализован как ServletContextListener, и то же самое упоминается в web.xml.

web.xml

<listener> 
    <listener-class>com.ehacampaign.helper.EHAJobSchedulerListener</listener-class> 
</listener> 

EHAJobSchedulerListener.java

public class EHAJobSchedulerListener implements ServletContextListener {..} 

Как вы можете видеть код, класс регистрируется в сети, и я не понимаю, почему он не может используйте источник данных в контейнере J2EE.

Вопросов:

  1. Почему сервлет зарегистрированный класс не может получить доступ к источник данных в J2EE контейнере?
  2. Если источник данных в контейнере не может быть использован, то как сделать подключение к БД при выполнении задания?

ПРИМЕЧАНИЕ. У меня такая же настройка в JBoss AS 7.1, и задания работают плавно, обращаясь к источнику данных, настроенному в JBoss AS 7.1. Я должен развивать это в Websphere, как этого требует его заказчик.

ОБНОВЛЕНО

Я приложил модифицированный файл свойств кварца. Даже после добавления workmanagerthread, я получаю ту же ошибку.

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 
+2

Вы используете WorkManagerThreadExecutor? Я предполагаю, что поиск выполняется на кварцевой нити. http://www.quartz-scheduler.org/api/2.2.1/org/quartz/commonj/WorkManagerThreadExecutor.html – Alasdair

+0

Что такое полная трассировка стека? Это скажет нам, действительно ли вы на управляемом потоке или нет, что, я подозреваю, так (и соответствует тому, что указывает сообщение об ошибке). Я тестировал это локально, и я смог найти источник данных из ServletContextListener без использования Quartz, поэтому я очень подозреваю, что Quartz запускает ваш код в не управляемом потоке. –

+0

@Alasdair, Да, поиск выполняется на кварцевой нити. Даже после изменения файла свойств он не работает. Нужно ли создавать рабочий менеджер в Websphere? – Anand

ответ

1

Для выполнения поиска JNDI в WebSpehre ваш код должен работать в управляемом потоке. Для того чтобы иметь Кварц работать на одной из управляемых потоков WebSphere, вы должны установить следующие 2 свойства в вашем quartz.properties (как Алистер упомянуто в комментариях):

org.quartz.threadExecutor.class=org.quartz.commonj.WorkManagerThreadExecutor 
org.quartz.threadExecutor.workManagerName=wm/default 

Имя для org.quartz.threadExecutor.workManagerName может быть имя JNDI любого Work Manager, который вы настроили в WebSphere. Я рекомендую просто использовать wm/default, потому что он находится в вашей конфигурации по умолчанию.

+0

Спасибо за ваш ответ. Я получил ошибку ClassNotFoundException для WorkManagerThreadExecutor. Затем выяснилось, что класс действительно находится в пакете org.quartz.commonj. * Я получаю сообщение об ошибке даже после изменения файла свойства. Пожалуйста, просмотрите содержимое моего файла свойства в моем сообщении (обновлено). – Anand

+1

Взгляд JNDI должен быть внутри конструктора. Он не будет работать, если его вне конструктора – Anand

+0

Спасибо, что указали это. Я обновил свой ответ. Вы заставляли это работать? Газ сделал хорошее предложение об удалении свойств .threadPool из файла quartz.properties –

0

При всей помощи, предоставляемой aguibert и Alasdair, и reference from here, я могу исправить проблему.

кварцевой файл свойство:

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 

Соединение с базой данных или JNDI поиска должно произойти в пустой конструктор JOB Реализован класс. Например,

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; 
} 
} 
+0

Обратите внимание, что ссылки на открытые соединения не должны храниться (особенно, когда задания выполняются на разных потоках). Объекты DataSource считаются потокобезопасными и могут храниться в течение длительных периодов времени, но Connections не должны и должны следовать шаблону get/use/close. Постоянное подключение к открытому соединению приведет к серьезным проблемам с производительностью и масштабируемостью. –

+0

@aguibert, Спасибо за ваши предложения. Фактически, я закрываю соединение в слое DAO после завершения операции DB. Я не упомянул код, чтобы закрыть соединение здесь, но я его обработал. Соединение для каждого потока закрывается после завершения задания. – Anand

Смежные вопросы