package eu.geoknow.generator.workflow;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URLDecoder;
import java.util.TreeMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.apache.log4j.Logger;
import org.springframework.schema.batch.Job;
import org.springframework.schema.batch.ObjectFactory;
import org.springframework.schema.batch.TaskletType;
import org.springframework.schema.beans.Bean;
import org.springframework.schema.beans.Beans;
import eu.geoknow.generator.workflow.beans.MultiStepJob;
import eu.geoknow.generator.workflow.beans.OneStepServiceJob;
import eu.geoknow.generator.workflow.beans.Step;
/**
* This class is used to create spring batch jobs definitions. This class is to
* be extended to be able to generate workflows of several steps.
*
* @author alejandragarciarojas
*
*/
public class JobFactory {
private static final Logger log = Logger.getLogger(JobFactory.class);
private org.springframework.schema.batch.ObjectFactory batchFactory;
private org.springframework.schema.beans.ObjectFactory beanFactory;
private static JobFactory instance;
/**
* Get the singleton instance of the job factory
* @return
* @throws Exception
*/
public static synchronized JobFactory getInstance() throws Exception {
if (instance != null)
return instance;
instance = new JobFactory();
instance.batchFactory = new org.springframework.schema.batch.ObjectFactory();
instance.beanFactory = new org.springframework.schema.beans.ObjectFactory();
return instance;
}
private Job createJob(ObjectFactory factory, String id, String description) {
Job job = factory.createJob();
job.setId(id);
job.setDescription(description);
// the job can be restarted
job.setRestartable("true");
return job;
}
/**
* Creates One-Step REST Service Job XML string
*
* @param jobId
* @param service
* @param contenttype
* @param method
* @param body
* @return
* @throws JAXBException
* @throws IOException
*/
public String createOneStepServiceJobXml(String jobId, String description,
String service, String contenttype, String method, String body) throws JAXBException,
IOException {
// creates the bean of the service with the corresponding parameters
Bean beanService = BeanFactory.createServiceTaskletBean(beanFactory, "beanService",
service, contenttype, method, body);
/*
* creates a new job of one step
*
* <batch:job id="limesJobSampleJsonss" restartable="true"
* incrementer="jobParamatersIncrementer"> <batch:step id="limesStep" >
* <batch:tasklet ref="serviceTasklet" /> </batch:step> </batch:job>
*/
TaskletType tasklet = batchFactory.createTaskletType();
tasklet.setRef("beanService");
org.springframework.schema.batch.Job.Step jobstep = batchFactory.createJobStep();
jobstep.setId("oneStep");
jobstep.setTasklet(tasklet);
Bean jobIncrementer = beanFactory.createBean();
jobIncrementer.setId("jobParamatersIncrementer");
jobIncrementer.setClazz("org.springframework.batch.core.launch.support.RunIdIncrementer");
Job job = createJob(batchFactory, jobId, description);
log.debug(job.getDescription());
job.getStepOrSplitOrFlow().add(jobstep);
job.setIncrementer("jobParamatersIncrementer");
// generates the root beans
Beans beans = beanFactory.createBeans();
beans.getImportOrAliasOrBean().add(job);
beans.getImportOrAliasOrBean().add(beanService);
beans.getImportOrAliasOrBean().add(jobIncrementer);
// write the xml to a string
StringWriter writer = new StringWriter();
final String location = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
+ " http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd"
+ " http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd";
Class[] classes = new Class[] { Beans.class, Bean.class, Job.class };
JAXBContext jaxbContext = JAXBContext.newInstance(classes);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
jaxbMarshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, location);
jaxbMarshaller.marshal(beans, writer);
log.debug(writer.toString());
// return the name of the job file generated
return writer.toString();
}
/**
* Creates a job based on the OneStepServiceJob bean. Notice that body
* requires URLEncoded.
*
* @param job
* @return String a XML string
* @throws Exception
*/
public String createOneStepServiceJobXml(OneStepServiceJob job) throws Exception {
log.debug(job.toString());
String xml = createOneStepServiceJobXml(job.getName(), "", job
.getService(), job.getContenttype(), job.getMethod(), URLDecoder.decode(job
.getBody(), "utf-8"));
return xml;
}
/**
* Creates Mulit-Step REST Service Job XML string
*
* @param msj the multistep object received from the REST API
* @return
* @throws Exception
*/
public String createMultiStepServiceJobXml(MultiStepJob msj) throws Exception {
//if no step, no job is created
if(msj.getSteps().size() == 0) throw new Exception("No steps, thus, no job.");
//create job bean
Bean jobIncrementer = beanFactory.createBean();
jobIncrementer.setId("jobParamatersIncrementer");
jobIncrementer.setClazz("org.springframework.batch.core.launch.support.RunIdIncrementer");
Job job = createJob(batchFactory, msj.getName(), "");
job.setIncrementer("jobParamatersIncrementer");
// generates the root beans
Beans rootBean = beanFactory.createBeans();
rootBean.getImportOrAliasOrBean().add(job);
rootBean.getImportOrAliasOrBean().add(jobIncrementer);
//iterate through the steps, create the beans and store their order
TreeMap<Integer,Bean> stepBeans = new TreeMap<Integer, Bean>();
for(Step s : msj.getSteps()){
Bean beanService = BeanFactory.createServiceTaskletBean(beanFactory, "beanService_"+msj.getName()+"_"+s.getNumberOfOrder(),
s.getService(), s.getContenttype(), s.getMethod(), URLDecoder.decode(s.getBody(), "utf-8"));
stepBeans.put(s.getNumberOfOrder(),beanService);
//add the service bean to the root
rootBean.getImportOrAliasOrBean().add(beanService);
}
//with the ordered list of the bean, create the tasklets and job steps, add them to the job
for(int i : stepBeans.keySet()){
TaskletType tasklet = batchFactory.createTaskletType();
tasklet.setRef("beanService_"+msj.getName()+"_"+i);
org.springframework.schema.batch.Job.Step jobstep = batchFactory.createJobStep();
jobstep.setId("multiStep_"+msj.getName()+"_"+i);
jobstep.setTasklet(tasklet);
//if there is a next step, add it as reference
//this creates a simple sequential flow
if((i+1) <= stepBeans.size()){
jobstep.setNext("multiStep_"+msj.getName()+"_"+(i+1));
}
job.getStepOrSplitOrFlow().add(jobstep);
}
// write the xml to a string
StringWriter writer = new StringWriter();
final String location = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
+ " http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd"
+ " http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd";
Class[] classes = new Class[] { Beans.class, Bean.class, Job.class };
JAXBContext jaxbContext = JAXBContext.newInstance(classes);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
jaxbMarshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, location);
jaxbMarshaller.marshal(rootBean, writer);
log.info(writer.toString());
// return the name of the job file generated
return writer.toString();
}
}