2010年1月15日 | 分类: java | 标签: , ,

Quartz is a great tool by which you could set up cron jobs inside your Java application. Spring makes even easier, but Spring doesn’t provide one function I want to achieve — dynamically managing Quartz jobs such as changing cron expression at runtime.

It was really easy to set up a Quartz job via Spring xml configuration based on the documentation (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/scheduling.html#scheduling-quartz.). But once the application starts up, configuration cannot be changed or in another word the change will not be accepted until a server bounce, which is an issue in the production environment. Also my Quartz jobs require my service layer and need to update database. Since they run separately from sessions controlled by OSIV and interceptor, my old friend ‘no session or session was close’ error was back.

So here are two problems I want to solve.

1. dynamically update (and create) Quartz jobs.
2. no session or session was close while trying to get a hibernate collection (lazy initialization problem outside the view)

I searched this problem for four hours and experienced many suggestions until I came across with this one @ http://tech.javayogi.com/spring-quartz-problem.html.

Its solution was to created an abstract Quartz job class that creates and closes a hibernate transaction. Simply inherit from the class, instead of directly from the Quartz Job class will solve that transcation problem.

import org.springframework.scheduling.quartz.*;
import org.springframework.orm.hibernate3.*;
import org.springframework.transaction.support.*;
import org.quartz.*;
import org.hibernate.*;
import org.hibernate.context.*;
import org.apache.log4j.*;

/**
* Hibernate/Spring can be a pain, because hibernate sessions are not propagated. For JSP pages there is an
* interceptor taking care of it. Quartz tasks are outside of the scope of the view interceptor. So, this
* class wraps a transaction around it and makes sure that hibernate POJOs can load lazily.
*
* Make sure that the spring reference to the hibernateSessionFactory is satisfied in the spring mapping.
*
* @author Thomas Fischer
*/
public abstract class TransactionalQuartzTask extends QuartzJobBean {
private static final Logger log = Logger.getLogger(TransactionalQuartzTask.class);

// spring injected reference
private SessionFactory hibernateSessionFactory;
/**
* Most of this method is copied from the HibernateInterceptor.
*/
protected final void executeInternal(JobExecutionContext ctx) throws JobExecutionException {

    Session session = SessionFactoryUtils.getSession(hibernateSessionFactory, true);
    boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getHibernateSessionFactory());
    if (existingTransaction) {
        log.debug("Found thread-bound Session for TransactionalQuartzTask");
    }
    else {
        TransactionSynchronizationManager.bindResource(getHibernateSessionFactory(), new SessionHolder(session));
    }

    try {
        executeTransactional(ctx);
    }
    catch (HibernateException ex) {
        throw ex;
    }
    finally {
        if (existingTransaction) {
             log.debug("Not closing pre-bound Hibernate Session after TransactionalQuartzTask");
        }
        else {
             TransactionSynchronizationManager.unbindResource(getHibernateSessionFactory());
             SessionFactoryUtils.releaseSession(session, getHibernateSessionFactory());
        }
    }
}

/**
 * Implementing classes, implement this method.
 */
protected abstract void executeTransactional(JobExecutionContext ctx) throws JobExecutionException;

public SessionFactory getHibernateSessionFactory() {
    return hibernateSessionFactory;
}

public void setHibernateSessionFactory(SessionFactory hibernateSessionFactory) {
    this.hibernateSessionFactory = hibernateSessionFactory;
}
}
2009年8月31日 | 分类: java, tomcat | 标签:

It is done by using one code base.

It turns out pretty easy..

I decide to run them as services so that they can be easily spotted in the Services GUI.

1. Download tomcat zip (not the windows installer one) and unzip to your destination.

2. Modify service.bat under bin by setting CATALINA_BASE to one of your instance directory which contains at least conf (change port number to be unique for each instance in server.xml), webapps (applications) and logs directories.

3. Run at cmd “service.bat install YOUR_PREFER_NAME”

4. Repeat 2-3 to configure more instances as services.

5. Go to Services GUI and start the services added..

That’s pretty much it.

It is done by using one code Tomcat base.

一台Windows机器同时运行多个Tomcat服务

2009年3月27日 | 分类: java | 标签: , , ,

I have been having troubles to make soap calls and didn’t know how to debug or show the soap messages sent until my co-worker advised me to try TCPMon.

intercept the soap message by using TCPMon.

  • change target web service URI:port in your soap client to your server:port, e.g. localhost:8888
  • create a new TCPMon and listen on the port, 8888
  • set up the forwarding port to the actual target web service URI and port, e.g. test.com:4041
  • add it to start listening the local port (8888) and run the soap client and check what’s being sent to the actual target server(test.com:4041)