/*
* Copyright (c) 2013 Red Hat, Inc. and/or its affiliates.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cheng Fang - Initial API and implementation
*/
package org.jberet.creation;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.batch.operations.JobStartException;
import javax.xml.stream.XMLResolver;
import javax.xml.stream.XMLStreamException;
import org.jberet._private.BatchMessages;
import org.jberet.job.model.BatchArtifacts;
import org.jberet.job.model.Job;
import org.jberet.job.model.JobMerger;
import org.jberet.job.model.JobParser;
import org.jberet.spi.JobXmlResolver;
import static org.jberet._private.BatchMessages.MESSAGES;
public class ArchiveXmlLoader {
public final static String ARCHIVE_JOB_XML_DIR = "META-INF/batch-jobs/";
public final static String ARCHIVE_BATCH_XML = "META-INF/batch.xml";
//public static final String JOB_XML_SCHEMA = "jobXML_1_0.xsd";
//public static final String BATCH_XML_SCHEMA = "batchXML_1_0.xsd";
// since inheritance is deferred from 1.0, this cache is not needed.
// private static ConcurrentMap<String, Object> loadedJobsByName = new ConcurrentHashMap<String, Object>();
/**
* Gets the batch artifacts definition object, loaded from the archive batch.xml if available.
*
* @param classLoader the application classloader used to load batch xml
* @return the batch artifacts definition object
*/
public static BatchArtifacts loadBatchXml(final ClassLoader classLoader) throws JobStartException {
BatchArtifacts batchArtifacts = null;
final InputStream is = classLoader.getResourceAsStream(ARCHIVE_BATCH_XML);
if (is == null) { //the app doesn't contain META-INF/batch.xml
return null;
}
try {
batchArtifacts = JobParser.parseBatchArtifacts(is);
} catch (Exception e) {
throw MESSAGES.failToParseBatchXml(e, ARCHIVE_BATCH_XML);
} finally {
try {
is.close();
} catch (IOException e) {
//ignore
}
}
return batchArtifacts;
}
/**
* Gets the job root element for a given job name.
*
* @param jobXmlName base name of the job xml document
* @param classLoader the class loader used to locate the job
* @param loadedJobs a collections of jobs that have already been loaded
* @param jobXmlResolver the job XML resolver
*
* @return the job root element
*
* @throws javax.batch.operations.JobStartException if the job failed to start
*/
public static Job loadJobXml(final String jobXmlName, final ClassLoader classLoader, final List<Job> loadedJobs, final JobXmlResolver jobXmlResolver)
throws JobStartException {
for (final Job j : loadedJobs) {
if (jobXmlName.equals(j.getJobXmlName() != null ? j.getJobXmlName() : j.getId())) {
return j;
}
}
Job job = null;
final InputStream is;
try {
is = getJobXml(jobXmlName, classLoader, jobXmlResolver);
} catch (final IOException e) {
throw MESSAGES.failToGetJobXml(e, jobXmlName);
}
try {
job = JobParser.parseJob(is, classLoader, new JobXmlEntityResolver(classLoader, jobXmlResolver));
if (!jobXmlName.equals(job.getId())) {
job.setJobXmlName(jobXmlName);
}
loadedJobs.add(job);
if (!job.getInheritingJobElements().isEmpty()) {
JobMerger.resolveInheritance(job, classLoader, loadedJobs, jobXmlResolver);
}
} catch (final Exception e) {
throw MESSAGES.failToParseJobXml(e, jobXmlName);
} finally {
if (is != null) {
try {
is.close();
} catch (final IOException e) {
//ignore
}
}
}
return job;
}
private static InputStream getJobXml(String jobXmlName, final ClassLoader classLoader, final JobXmlResolver jobXmlResolver) throws IOException {
if (!jobXmlName.endsWith(".xml")) {
jobXmlName += ".xml";
}
// Use the SPI to locate the job XML
final InputStream is = jobXmlResolver.resolveJobXml(jobXmlName, classLoader);
if (is != null) {
return is;
}
throw BatchMessages.MESSAGES.failToGetJobXml(jobXmlName);
}
private static class JobXmlEntityResolver implements XMLResolver {
private final ClassLoader classLoader;
private final JobXmlResolver jobXmlResolver;
private JobXmlEntityResolver(final ClassLoader classLoader, final JobXmlResolver jobXmlResolver) {
this.classLoader = classLoader;
this.jobXmlResolver = jobXmlResolver;
}
@Override
public Object resolveEntity(final String publicID, final String systemID, final String baseURI, final String namespace) throws XMLStreamException {
try {
return getJobXml(systemID, classLoader, jobXmlResolver);
} catch (IOException e) {
throw new XMLStreamException(e);
}
}
}
}