/*
* #%L
* Talend ESB :: Camel Talend Job Component
* %%
* Copyright (C) 2011 - 2014 Talend Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.talend.camel;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import org.apache.camel.Exchange;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.impl.DefaultProducer;
import org.apache.camel.util.ObjectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import routines.system.api.TalendESBRoute;
import routines.system.api.TalendJob;
/**
* <p>
* The Talend producer.
* </p>
*/
public class TalendProducer extends DefaultProducer {
private static final transient Logger LOG = LoggerFactory.getLogger(TalendProducer.class);
private Thread workingThread;
private TalendJob jobInstance;
public TalendProducer(TalendEndpoint endpoint) {
super(endpoint);
}
public void process(Exchange exchange) throws Exception {
final TalendEndpoint talendEndpoint = (TalendEndpoint) getEndpoint();
final String context = talendEndpoint.getContext();
final Collection<String> args = new ArrayList<String>();
if (context != null) {
args.add("--context=" + context);
}
if (talendEndpoint.isPropagateHeader()) {
getParamsFromHeaders(exchange, args);
}
getParamsFromProperties(getEndpoint().getCamelContext().getProperties(), args);
getParamsFromProperties(talendEndpoint.getEndpointProperties(), args);
boolean success = false;
TalendJob jobInstance = getJobInstance();
try {
invokeTalendJob(jobInstance, args.toArray(new String[args.size()]), exchange);
jobDone();
success = true;
} finally {
if (!success) {
jobDown();
}
}
}
private static void getParamsFromProperties(Map<String, String> propertiesMap, Collection<String> args) {
if (propertiesMap != null) {
for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
args.add("--context_param " + entry.getKey() + '=' + entry.getValue());
}
}
}
private static void getParamsFromHeaders(
Exchange exchange, Collection<String> args) {
Map<String, Object> headers = exchange.getIn().getHeaders();
for (Map.Entry<String, Object> header : headers.entrySet()) {
Object headerValue = header.getValue();
if (headerValue != null) {
String headerStringValue = exchange.getContext().getTypeConverter()
.convertTo(String.class, exchange, headerValue);
args.add("--context_param " + header.getKey() + '=' + headerStringValue);
}
}
}
private void invokeTalendJob(final TalendJob jobInstance, String[] args, Exchange exchange) {
try {
final Method setExchangeMethod =
jobInstance.getClass().getMethod("setExchange", new Class[]{Exchange.class});
LOG.debug("Pass the exchange from route to Job");
ObjectHelper.invokeMethod(setExchangeMethod, jobInstance, exchange);
} catch (NoSuchMethodException e) {
LOG.debug("No setExchange(exchange) method found in Job, the message data will be ignored");
}
if (LOG.isDebugEnabled()) {
LOG.debug("Invoking Talend job '" + jobInstance.getClass().getCanonicalName()
+ ".runJob(String[] args)' with args: " + Arrays.toString(args));
}
// use local variable due to single component instance during parallel processing
final Thread thread = Thread.currentThread();
workingThread = thread;
final ClassLoader oldContextCL = thread.getContextClassLoader();
try {
thread.setContextClassLoader(jobInstance.getClass().getClassLoader());
int result = jobInstance.runJobInTOS(args);
if (result != 0) {
throw new RuntimeCamelException("Execution of Talend job '"
+ jobInstance.getClass().getCanonicalName() + "' with args: "
+ Arrays.toString(args) + "' failed, see stderr for details");
// Talend logs errors using System.err.println
}
} finally {
thread.setContextClassLoader(oldContextCL);
workingThread = null;
}
}
@Override
protected void doStop() throws Exception {
super.doStop();
boolean success = false;
try {
TalendJob wjob = jobInstance;
if (wjob instanceof TalendESBRoute) {
((TalendESBRoute) wjob).stop();
LOG.info("Job instance stopped.");
wait(100L);
}
success = true;
} finally {
Thread wthread = workingThread;
if (null != wthread) {
LOG.info("Enforce Talend job termination.");
wthread.interrupt();
}
if (!success) {
jobDown();
}
}
}
@Override
protected void doShutdown() throws Exception {
super.doShutdown();
jobDown();
}
private TalendJob getJobInstance() throws Exception {
if (jobInstance == null) {
jobInstance = ((TalendEndpoint) getEndpoint()).getJobInstance();
LOG.debug("Getting new job instance.");
} else {
LOG.debug("Re-using sticky job instance.");
}
return jobInstance;
}
private void jobDone() throws Exception {
if (!((TalendEndpoint) getEndpoint()).isStickyJob()) {
jobDown();
}
}
private void jobDown() throws Exception {
TalendJob job = jobInstance;
jobInstance = null;
if (job instanceof TalendESBRoute) {
((TalendESBRoute) job).shutdown();
LOG.info("Job instance shut down.");
}
}
}