Tuesday, August 5, 2014

configure spring batch as window service

The target to configure this spring batch job demo as window service to run and manage.

1) download java service wrapper from http://wrapper.tanukisoftware.com/doc/english/download.jsp and decompress the zip file

2) use the method3 for integration, refer to http://wrapper.tanukisoftware.com/doc/english/integrate-listener.html

3) in order to integrate the service wrapper, we need a Main class

package wx.batch1;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.tanukisoftware.wrapper.WrapperListener;
import org.tanukisoftware.wrapper.WrapperManager;

public class MyWrapper implements WrapperListener {

private ClassPathXmlApplicationContext context;

/*---------------------------------------------------------------
* Constructors
*-------------------------------------------------------------*/
private MyWrapper() {
}

/**
* Called whenever the native Wrapper code traps a system control signal
* against the Java process. It is up to the callback to take any actions
* necessary. Possible values are: WrapperManager.WRAPPER_CTRL_C_EVENT,
* WRAPPER_CTRL_CLOSE_EVENT, WRAPPER_CTRL_LOGOFF_EVENT, or
* WRAPPER_CTRL_SHUTDOWN_EVENT
*
* @param event
*            The system control signal.
*/
public void controlEvent(int event) {
if ((event == WrapperManager.WRAPPER_CTRL_LOGOFF_EVENT)
&& (WrapperManager.isLaunchedAsService() || WrapperManager
.isIgnoreUserLogoffs())) {
// Ignore
} else {
WrapperManager.stop(0);
// Will not get here.
}

}

/*---------------------------------------------------------------
* WrapperListener Methods
*-------------------------------------------------------------*/
/**
* The start method is called when the WrapperManager is signaled by the
* native Wrapper code that it can start its application. This method call
* is expected to return, so a new thread should be launched if necessary.
*
* @param args
*            List of arguments used to initialize the application.
*
* @return Any error code if the application should exit on completion of
*         the start method. If there were no problems then this method
*         should return null.
*/
public Integer start(String[] arg) {

// load spring configure file and launch it
context = new ClassPathXmlApplicationContext("classpath:app-context.xml");
context.start();
WrapperManager.signalStarting(30000);
return null;
}

/**
* Called when the application is shutting down. The Wrapper assumes that
* this method will return fairly quickly. If the shutdown code code could
* potentially take a long time, then WrapperManager.signalStopping() should
* be called to extend the timeout period. If for some reason, the stop
* method can not return, then it must call WrapperManager.stopped() to
* avoid warning messages from the Wrapper.
*
* @param exitCode
*            The suggested exit code that will be returned to the OS when
*            the JVM exits.
*
* @return The exit code to actually return to the OS. In most cases, this
*         should just be the value of exitCode, however the user code has
*         the option of changing the exit code if there are any problems
*         during shutdown.
*/
public int stop(int exitCode) {
// shutdown spring context
context.registerShutdownHook();

WrapperManager.signalStopping(60000);
return exitCode;
}

/*---------------------------------------------------------------
* Main Method
*-------------------------------------------------------------*/
public static void main(String[] args) {
// Start the application. If the JVM was launched from the native
// Wrapper then the application will wait for the native Wrapper to
// call the application's start method. Otherwise the start method
// will be called immediately.
WrapperManager.start(new MyWrapper(), args);
}
}

4) compile above main class with demo together and generate a jar file batch1.jar

5) create a folder structure as follows,

/bin - copy from step 1
/con
  | - wrapper.conf    //-- copy from step 1
  |- app-context.xml
  |- spring-batch1.xml
/lib
  |- batch1.jar
  |- wrapper.jar   // copy from step 1
  |- wrapper.dll   // copy from step 1
  |- spring-batch-core-2.2.7.RELEASE.jar
  ...... all the other dependencies
/logs   

6) open the wrapper.conf and edit it (the changes are highlighted in red)

#encoding=UTF-8
# Configuration files must begin with a line specifying the encoding
#  of the the file.

#********************************************************************
# Wrapper License Properties (Ignored by Community Edition)
#********************************************************************
# Professional and Standard Editions of the Wrapper require a valid
#  License Key to start.  Licenses can be purchased or a trial license
#  requested on the following pages:
# http://wrapper.tanukisoftware.com/purchase
# http://wrapper.tanukisoftware.com/trial

# Include file problems can be debugged by removing the first '#'
#  from the following line:
##include.debug

# The Wrapper will look for either of the following optional files for a
#  valid License Key.  License Key properties can optionally be included
#  directly in this configuration file.
#include ../conf/wrapper-license.conf
#include ../conf/wrapper-license-%WRAPPER_HOST_NAME%.conf

# The following property will output information about which License Key(s)
#  are being found, and can aid in resolving any licensing problems.
#wrapper.license.debug=TRUE

#********************************************************************
# Wrapper Localization
#********************************************************************
# Specify the locale which the Wrapper should use.  By default the system
#  locale is used.
#wrapper.lang=en_US # en_US or ja_JP

# Specify the location of the Wrapper's language resources.  If these are
#  missing, the Wrapper will default to the en_US locale.
wrapper.lang.folder=../lang

#********************************************************************
# Wrapper Java Properties
#********************************************************************
# Java Application
#  Locate the java binary on the system PATH:
wrapper.java.command=C:/jdk1.6.0_45/bin/java
#  Specify a specific java binary:
#set.JAVA_HOME=/java/path
#wrapper.java.command=%JAVA_HOME%/bin/java

# Tell the Wrapper to log the full generated Java command line.
#wrapper.java.command.loglevel=INFO

# Java Main class.  This class must implement the WrapperListener interface
#  or guarantee that the WrapperManager class is initialized.  Helper
#  classes are provided to do this for you.  See the Integration section
#  of the documentation for details.
wrapper.java.mainclass=wx.batch1.MyWrapper

# Java Classpath (include wrapper.jar)  Add class path elements as
#  needed starting from 1
wrapper.java.classpath.1=../conf
wrapper.java.classpath.2=../lib/wrapper.jar
wrapper.java.classpath.3=../lib/mysql-connector-java-5.1.30.jar
wrapper.java.classpath.4=../lib/spring-batch-core-2.2.7.RELEASE.jar
wrapper.java.classpath.5=../lib/spring-core-3.2.10.RELEASE.jar
wrapper.java.classpath.6=../lib/spring-jdbc-3.2.10.RELEASE.jar
wrapper.java.classpath.7=../lib/batch1.jar
wrapper.java.classpath.8=../lib/spring-context-3.2.10.RELEASE.jar
wrapper.java.classpath.9=../lib/spring-beans-3.2.10.RELEASE.jar
wrapper.java.classpath.10=../lib/commons-logging-1.1.1.jar
wrapper.java.classpath.11=../lib/spring-expression-3.2.10.RELEASE.jar
wrapper.java.classpath.12=../lib/spring-retry-1.0.2.RELEASE.jar
wrapper.java.classpath.13=../lib/spring-tx-3.2.10.RELEASE.jar
wrapper.java.classpath.14=../lib/spring-batch-infrastructure-2.2.7.RELEASE.jar
wrapper.java.classpath.15=../lib/spring-aop-3.2.10.RELEASE.jar
wrapper.java.classpath.16=../lib/aopalliance-1.0.jar
wrapper.java.classpath.17=../lib/xstream-1.3.1.jar
wrapper.java.classpath.18=../lib/org.apache.servicemix.bundles.jettison-1.0.1_1.jar

# Java Library Path (location of Wrapper.DLL or libwrapper.so)
wrapper.java.library.path.1=../lib

# Java Bits.  On applicable platforms, tells the JVM to run in 32 or 64-bit mode.
wrapper.java.additional.auto_bits=TRUE

# Java Additional Parameters
wrapper.java.additional.1=

# Initial Java Heap Size (in MB)
wrapper.java.initmemory=100

# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=500

# Application parameters.  Add parameters as needed starting from 1
#wrapper.app.parameter.1=

#********************************************************************
# Wrapper Logging Properties
#********************************************************************
# Enables Debug output from the Wrapper.
# wrapper.debug=TRUE

# Format of output for the console.  (See docs for formats)
wrapper.console.format=PM

# Log Level for console output.  (See docs for log levels)
wrapper.console.loglevel=INFO

# Log file to use for wrapper output logging.
wrapper.logfile=../logs/wrapper.log

# Format of output for the log file.  (See docs for formats)
wrapper.logfile.format=LPTM

# Log Level for log file output.  (See docs for log levels)
wrapper.logfile.loglevel=INFO

# Maximum size that the log file will be allowed to grow to before
#  the log is rolled. Size is specified in bytes.  The default value
#  of 0, disables log rolling.  May abbreviate with the 'k' (kb) or
#  'm' (mb) suffix.  For example: 10m = 10 megabytes.
wrapper.logfile.maxsize=0

# Maximum number of rolled log files which will be allowed before old
#  files are deleted.  The default value of 0 implies no limit.
wrapper.logfile.maxfiles=0

# Log Level for sys/event log output.  (See docs for log levels)
wrapper.syslog.loglevel=NONE

#********************************************************************
# Wrapper General Properties
#********************************************************************
# Allow for the use of non-contiguous numbered properties
wrapper.ignore_sequence_gaps=TRUE

# Do not start if the pid file already exists.
wrapper.pidfile.strict=TRUE

# Title to use when running as a console
wrapper.console.title=Test Wrapper Sample Application

#********************************************************************
# Wrapper JVM Checks
#********************************************************************
# Detect DeadLocked Threads in the JVM. (Requires Standard Edition)
wrapper.check.deadlock=TRUE
wrapper.check.deadlock.interval=10
wrapper.check.deadlock.action=RESTART
wrapper.check.deadlock.output=FULL

# Out Of Memory detection.
# (Ignore output from dumping the configuration to the console.  This is only needed by the TestWrapper sample application.)
wrapper.filter.trigger.999=wrapper.filter.trigger.*java.lang.OutOfMemoryError
wrapper.filter.allow_wildcards.999=TRUE
wrapper.filter.action.999=NONE
#  Ignore -verbose:class output to avoid false positives.
wrapper.filter.trigger.1000=[Loaded java.lang.OutOfMemoryError
wrapper.filter.action.1000=NONE
# (Simple match)
wrapper.filter.trigger.1001=java.lang.OutOfMemoryError
# (Only match text in stack traces if -XX:+PrintClassHistogram is being used.)
#wrapper.filter.trigger.1001=Exception in thread "*" java.lang.OutOfMemoryError
#wrapper.filter.allow_wildcards.1001=TRUE
wrapper.filter.action.1001=RESTART
wrapper.filter.message.1001=The JVM has run out of memory.

#********************************************************************
# Wrapper Email Notifications. (Requires Professional Edition)
#********************************************************************
# Common Event Email settings.
#wrapper.event.default.email.debug=TRUE
#wrapper.event.default.email.smtp.host=<SMTP_Host>
#wrapper.event.default.email.smtp.port=25
#wrapper.event.default.email.subject=[%WRAPPER_HOSTNAME%:%WRAPPER_NAME%:%WRAPPER_EVENT_NAME%] Event Notification
#wrapper.event.default.email.sender=<Sender email>
#wrapper.event.default.email.recipient=<Recipient email>

# Configure the log attached to event emails.
#wrapper.event.default.email.attach_log=TRUE
#wrapper.event.default.email.maillog.lines=50
#wrapper.event.default.email.maillog.format=LPTM
#wrapper.event.default.email.maillog.loglevel=INFO

# Enable specific event emails.
#wrapper.event.wrapper_start.email=TRUE
#wrapper.event.jvm_prelaunch.email=TRUE
#wrapper.event.jvm_start.email=TRUE
#wrapper.event.jvm_started.email=TRUE
#wrapper.event.jvm_deadlock.email=TRUE
#wrapper.event.jvm_stop.email=TRUE
#wrapper.event.jvm_stopped.email=TRUE
#wrapper.event.jvm_restart.email=TRUE
#wrapper.event.jvm_failed_invocation.email=TRUE
#wrapper.event.jvm_max_failed_invocations.email=TRUE
#wrapper.event.jvm_kill.email=TRUE
#wrapper.event.jvm_killed.email=TRUE
#wrapper.event.jvm_unexpected_exit.email=TRUE
#wrapper.event.wrapper_stop.email=TRUE

# Specify custom mail content
wrapper.event.jvm_restart.email.body=The JVM was restarted.\n\nPlease check on its status.\n

#********************************************************************
# Wrapper Windows NT/2000/XP Service Properties
#********************************************************************
# WARNING - Do not modify any of these properties when an application
#  using this configuration file has been installed as a service.
#  Please uninstall the service before modifying this section.  The
#  service can then be reinstalled.

# Name of the service
wrapper.name=mybatch1

# Display name of the service
wrapper.displayname=My Batch1 Wrapper App

# Description of the service
wrapper.description=My Batch1 Wrapper App

# Service dependencies.  Add dependencies as needed starting from 1
wrapper.ntservice.dependency.1=

# Mode in which the service is installed.  AUTO_START, DELAY_START or DEMAND_START
wrapper.ntservice.starttype=AUTO_START

# Allow the service to interact with the desktop.
wrapper.ntservice.interactive=false

7) go to /bin folder and run InstallTestWrapper-NT.bat to install the service to window OS







then you can run/stop the service by right-click the new added service.

Or run TestWrapper.bat to test but not as window service

this is the log sample

INFO   | jvm 1    | 2014/08/05 12:30:22 | Aug 5, 2014 12:30:22 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO   | jvm 1    | 2014/08/05 12:30:22 | INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1cb8deef: startup date [Tue Aug 05 12:30:22 SGT 2014]; root of context hierarchy
INFO   | jvm 1    | 2014/08/05 12:30:22 | Aug 5, 2014 12:30:22 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO   | jvm 1    | 2014/08/05 12:30:22 | INFO: Loading XML bean definitions from class path resource [app-context.xml]
INFO   | jvm 1    | 2014/08/05 12:30:22 | Aug 5, 2014 12:30:22 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO   | jvm 1    | 2014/08/05 12:30:22 | INFO: Loading XML bean definitions from class path resource [spring-batch1.xml]
INFO   | jvm 1    | 2014/08/05 12:30:22 | Aug 5, 2014 12:30:22 PM org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
INFO   | jvm 1    | 2014/08/05 12:30:22 | INFO: Overriding bean definition for bean 'batch1': replacing [Generic bean: class [org.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Generic bean: class [org.springframework.batch.core.configuration.xml.JobParserJobFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
INFO   | jvm 1    | 2014/08/05 12:30:22 | Aug 5, 2014 12:30:22 PM org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
INFO   | jvm 1    | 2014/08/05 12:30:22 | INFO: Overriding bean definition for bean 'batch2': replacing [Generic bean: class [org.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Generic bean: class [org.springframework.batch.core.configuration.xml.JobParserJobFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
INFO   | jvm 1    | 2014/08/05 12:30:22 | Aug 5, 2014 12:30:22 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO   | jvm 1    | 2014/08/05 12:30:22 | INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@538d7ace: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,dataSource,jobRepository,transactionManager,jobLauncher,org.springframework.batch.core.scope.internalStepScope,org.springframework.beans.factory.config.CustomEditorConfigurer,org.springframework.batch.core.configuration.xml.CoreNamespacePostProcessor,step1,batch1,step2,batch2,org.springframework.context.annotation.internalAsyncAnnotationProcessor,org.springframework.context.annotation.internalScheduledAnnotationProcessor,org.springframework.scheduling.support.ScheduledMethodRunnable#0,org.springframework.scheduling.config.CronTask#0,org.springframework.scheduling.support.ScheduledMethodRunnable#1,org.springframework.scheduling.config.CronTask#1,org.springframework.scheduling.config.ContextLifecycleScheduledTaskRegistrar#0,helloTasklet,helloTasklet2,launch1,launch2,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
INFO   | jvm 1    | 2014/08/05 12:30:22 | Aug 5, 2014 12:30:22 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO   | jvm 1    | 2014/08/05 12:30:22 | INFO: Loaded JDBC driver: com.mysql.jdbc.Driver
INFO   | jvm 1    | 2014/08/05 12:30:22 | Aug 5, 2014 12:30:22 PM org.springframework.batch.core.launch.support.SimpleJobLauncher afterPropertiesSet
INFO   | jvm 1    | 2014/08/05 12:30:22 | INFO: No TaskExecutor has been set, defaulting to synchronous executor.
INFO   | jvm 1    | 2014/08/05 12:30:24 | Aug 5, 2014 12:30:24 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO   | jvm 1    | 2014/08/05 12:30:24 | INFO: Job: [FlowJob: [name=batch2]] launched with the following parameters: [{time=1407213024002}]
INFO   | jvm 1    | 2014/08/05 12:30:24 | Aug 5, 2014 12:30:24 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO   | jvm 1    | 2014/08/05 12:30:24 | INFO: Executing step: [step2]
INFO   | jvm 1    | 2014/08/05 12:30:24 | Hello World22222 Tue Aug 05 12:30:24 SGT 2014
INFO   | jvm 1    | 2014/08/05 12:30:24 | Aug 5, 2014 12:30:24 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO   | jvm 1    | 2014/08/05 12:30:24 | INFO: Job: [FlowJob: [name=batch2]] completed with the following parameters: [{time=1407213024002}] and the following status: [COMPLETED]
INFO   | jvm 1    | 2014/08/05 12:30:25 | Aug 5, 2014 12:30:25 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO   | jvm 1    | 2014/08/05 12:30:25 | INFO: Job: [FlowJob: [name=batch1]] launched with the following parameters: [{time=1407213025001}]
INFO   | jvm 1    | 2014/08/05 12:30:25 | Aug 5, 2014 12:30:25 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO   | jvm 1    | 2014/08/05 12:30:25 | INFO: Executing step: [step1]
INFO   | jvm 1    | 2014/08/05 12:30:25 | Hello World Tue Aug 05 12:30:25 SGT 2014
INFO   | jvm 1    | 2014/08/05 12:30:25 | Aug 5, 2014 12:30:25 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO   | jvm 1    | 2014/08/05 12:30:25 | INFO: Job: [FlowJob: [name=batch1]] completed with the following parameters: [{time=1407213025001}] and the following status: [COMPLETED]
INFO   | jvm 1    | 2014/08/05 12:30:30 | Aug 5, 2014 12:30:30 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO   | jvm 1    | 2014/08/05 12:30:30 | INFO: Job: [FlowJob: [name=batch1]] launched with the following parameters: [{time=1407213030002}]
INFO   | jvm 1    | 2014/08/05 12:30:30 | Aug 5, 2014 12:30:30 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO   | jvm 1    | 2014/08/05 12:30:30 | INFO: Executing step: [step1]
INFO   | jvm 1    | 2014/08/05 12:30:30 | Hello World Tue Aug 05 12:30:30 SGT 2014
INFO   | jvm 1    | 2014/08/05 12:30:30 | Aug 5, 2014 12:30:30 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO   | jvm 1    | 2014/08/05 12:30:30 | INFO: Job: [FlowJob: [name=batch1]] completed with the following parameters: [{time=1407213030002}] and the following status: [COMPLETED]
INFO   | jvm 1    | 2014/08/05 12:30:32 | Aug 5, 2014 12:30:32 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO   | jvm 1    | 2014/08/05 12:30:32 | INFO: Job: [FlowJob: [name=batch2]] launched with the following parameters: [{time=1407213032002}]
INFO   | jvm 1    | 2014/08/05 12:30:32 | Aug 5, 2014 12:30:32 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO   | jvm 1    | 2014/08/05 12:30:32 | INFO: Executing step: [step2]
INFO   | jvm 1    | 2014/08/05 12:30:32 | Hello World22222 Tue Aug 05 12:30:32 SGT 2014
INFO   | jvm 1    | 2014/08/05 12:30:32 | Aug 5, 2014 12:30:32 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO   | jvm 1    | 2014/08/05 12:30:32 | INFO: Job: [FlowJob: [name=batch2]] completed with the following parameters: [{time=1407213032002}] and the following status: [COMPLETED]
INFO   | jvm 1    | 2014/08/05 12:30:35 | Aug 5, 2014 12:30:35 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO   | jvm 1    | 2014/08/05 12:30:35 | INFO: Job: [FlowJob: [name=batch1]] launched with the following parameters: [{time=1407213035001}]
INFO   | jvm 1    | 2014/08/05 12:30:35 | Aug 5, 2014 12:30:35 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO   | jvm 1    | 2014/08/05 12:30:35 | INFO: Executing step: [step1]
INFO   | jvm 1    | 2014/08/05 12:30:35 | Hello World Tue Aug 05 12:30:35 SGT 2014
INFO   | jvm 1    | 2014/08/05 12:30:35 | Aug 5, 2014 12:30:35 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO   | jvm 1    | 2014/08/05 12:30:35 | INFO: Job: [FlowJob: [name=batch1]] completed with the following parameters: [{time=1407213035001}] and the following status: [COMPLETED]
STATUS | wrapper  | 2014/08/05 12:30:35 | <-- Wrapper Stopped

No comments:

Post a Comment