/* * Copyright (c) 2016 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.camel.component; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.Set; import javax.batch.operations.JobOperator; import javax.batch.runtime.JobExecution; import _private.JBeretCamelMessages; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.impl.DefaultProducer; /** * Camel producer class defining JBeret producer. This producer supports the * following URI structure (examples are given): * <ul> * <li>{@code jberet:jobs}<p> * lists job names. The response type is {@code java.util.Set<String>}. * <li>{@code jberet:jobs/job1}<p> * starts the job {@code job1}. any job parameters * should be passed as message body as {@code java.util.Properties}. * The response type is {@code long} (job execution id). * <li>{@code jberet:jobs/job1/start}<p> * starts the job {@code job1}, same as above. any job parameters * should be passed as message body as {@code java.util.Properties}. * The response type is {@code long} (job execution id). * <li>{@code jberet:jobinstances?jobName=job1&start=0&count=10}<p> * lists job instances, {@code jobName} query param is required, {@code start} * and {@code count} query params are both optional, and defaults to 0 and 10, * respectively. The response type is {@code java.util.List<JobInstance>}. * <li>{@code jberet:jobinstances/count?jobName=job1}<p> * counts job instances of the job {@code job1}. {@code jobName} query param is * required. The response type is {@code int}. * <li>{@code jberet:jobexecutions/running?jobName=job1}<p> * lists all running job executions of the job {@code job1}. {@code jobName} query param * is usually specified, but if omitted, it defaults to {@code *} and lists running * job executions of all jobs currently known to the batch runtime. * The response type is {@code java.util.List<Long>} (job execution ids). * <li>{@code jberet:jobexecutions/123456}<p> * gets the job execution with id {@code 123456}. * The response type is {@code JobExecution}. * <li>{@code jberet:jobexecutions/123456/stop}<p> * stops the job execution with id {@code 123456}. No response is generated. * <li>{@code jberet:jobexecutions/123456/restart}<p> * restarts the job execution with id {@code 123456}. any job parameters * should be passed as message body as {@code java.util.Properties}. * The response type is {@code long} (job execution id). * <li>{@code jberet:jobexecutions/123456/abandon}<p> * abandons the job execution with id {@code 123456}. No response is generated. * </ul> * * @see JBeretComponent * @see JBeretEndpoint * @since 1.3.0 */ public class JBeretProducer extends DefaultProducer { /** * String constant for "jobs", which typically appear in JBeret endpoint URI * to denote job-related operations. */ public static final String JOBS = "jobs"; /** * String constant for "jobinstances", which typically appear in JBeret endpoint URI * to denote jobinstance-related operations. */ public static final String JOBINSTANCES = "jobinstances"; /** * String constant for "jobexecutions", which typically appear in JBeret endpoint URI * to denote jobexecution-related operations. */ public static final String JOBEXECUTIONS = "jobexecutions"; /** * String constant for "start", which typically appear in JBeret endpoint URI * to denote starting a job, or the starting position inside a collection. */ public static final String START = "start"; /** * String constant for "restart", which usually appear in JBeret endpoint URI * to denote restarting a job execution. */ public static final String RESTART = "restart"; /** * String constant for "stop", which usually appear in JBeret endpoint URI * to denote stopping a running job execution. */ public static final String STOP = "stop"; /** * String constant for "abandon", which usually appear in JBeret endpoint URI * to denote abandoning a job execution. */ public static final String ABANDON = "abandon"; /** * String constant for "count", which usually appear in JBeret endpoint URI * to denote the query parameter {@code count}. */ public static final String COUNT = "count"; /** * String constant for "jobName", which usually appear in JBeret endpoint URI * to denote the query parameter {@code jobName}. */ public static final String JOB_NAME = "jobName"; /** * String constant for "running", which usually appear in JBeret endpoint URI * to denote running job executions. */ public static final String RUNNING = "running"; /** * Instantiates {@code JBeretProducer}. * * @param endpoint JBeret endpoint */ public JBeretProducer(final Endpoint endpoint) { super(endpoint); } /** * {@inheritDoc} * <p> * This method invokes the appropriate batch job operations as specified in * the message. * * @param exchange the current Camel exchange * @throws Exception if any errors occur */ @Override public void process(final Exchange exchange) throws Exception { final JBeretEndpoint endpoint = (JBeretEndpoint) getEndpoint(); final JBeretComponent component = (JBeretComponent) endpoint.getComponent(); runJobOperation(component.getJobOperator(), exchange, endpoint.getRemainingPath()); } /** * Runs various {@code JobOperator} operations based on JBeret endpoint URI. * * @param jobOperator batch job operator * @param exchange Camel exchange * @param remainingPath the remaing path of JBeret endpoint URI (without scheme part) * * @throws Exception if any errors occur */ private void runJobOperation(final JobOperator jobOperator, final Exchange exchange, final String remainingPath) throws Exception { if (remainingPath.isEmpty()) { throw JBeretCamelMessages.MESSAGES.invalidJBeretComponentUri(remainingPath); } final String[] parts = remainingPath.split("/"); if (parts.length == 0) { throw JBeretCamelMessages.MESSAGES.invalidJBeretComponentUri(remainingPath); } else { final String resourceType = parts[0].toLowerCase(); if (resourceType.equals(JOBS)) { doJobs(jobOperator, exchange, parts); } else if (JOBEXECUTIONS.equals(resourceType)) { doJobExecutions(jobOperator, exchange, parts); } else if (JOBINSTANCES.equals(resourceType)) { doJobInstances(jobOperator, exchange, parts); } else { throw JBeretCamelMessages.MESSAGES.invalidJBeretComponentUri(remainingPath); } } } /** * Performs operations related to "jobs", if "jobs" is the first segment of the URI. * * @param jobOperator batch job operator * @param exchange Camel exchange * @param paths string array containing segments of the URI path (without scheme part) * * @throws Exception if any errors occur */ private void doJobs(final JobOperator jobOperator, final Exchange exchange, final String[] paths) throws Exception { final Message in = exchange.getIn(); if (paths.length == 1) { //urls like jberet:jobs in.setBody(jobOperator.getJobNames(), Set.class); } else if (paths.length == 2) { //urls like jberet:jobs/job1 in.setBody(jobOperator.start(paths[1], (Properties) in.getBody()), long.class); } else if (paths.length == 3) { //urls like jberet:jobs/job1/start if (START.equals(paths[2])) { in.setBody(jobOperator.start(paths[1], (Properties) in.getBody()), long.class); } else { throw JBeretCamelMessages.MESSAGES.invalidJBeretComponentUri(Arrays.toString(paths)); } } else { throw JBeretCamelMessages.MESSAGES.invalidJBeretComponentUri(Arrays.toString(paths)); } } /** * Performs operations related to "jobinstances", if "jobinstances" is the first segment of the URI. * * @param jobOperator batch job operator * @param exchange Camel exchange * @param paths string array containing segments of the URI path (without scheme part) * @throws Exception if any errors occur */ private void doJobInstances(final JobOperator jobOperator, final Exchange exchange, final String[] paths) throws Exception { final Message in = exchange.getIn(); if (paths.length == 1) { //urls like jberet:jobinstances?jobName=job1&start=0&count=10 final String jobName = ((JBeretEndpoint) getEndpoint()).getJobName(); if (jobName == null) { throw JBeretCamelMessages.MESSAGES.invalidOrMissingParameterInJBeretComponentUrk(JOB_NAME, null); } final int startInt = ((JBeretEndpoint) getEndpoint()).getStart(); final int countInt = ((JBeretEndpoint) getEndpoint()).getCount(); in.setBody(jobOperator.getJobInstances(jobName, startInt, countInt), List.class); } else if (paths.length == 2) { //urls like jberet:jobinstances/count?jobName=job1 final String resourceName = paths[1]; if (COUNT.equals(resourceName)) { final String jobName = ((JBeretEndpoint) getEndpoint()).getJobName(); if (jobName == null) { throw JBeretCamelMessages.MESSAGES.invalidOrMissingParameterInJBeretComponentUrk(JOB_NAME, null); } in.setBody(jobOperator.getJobInstanceCount(jobName), int.class); } else { //urls like jberet:jobinstances/123456, //wait for the spec to support getJobInstanceById(instanceId) throw JBeretCamelMessages.MESSAGES.invalidJBeretComponentUri(Arrays.toString(paths)); } } else { throw JBeretCamelMessages.MESSAGES.invalidJBeretComponentUri(Arrays.toString(paths)); } } /** * Performs operations related to "jobexecutions", if "jobexecutions" is the first segment of the URI. * * @param jobOperator batch job operator * @param exchange Camel exchange * @param paths string array containing segments of the URI path (without scheme part) * @throws Exception if any errors occur */ private void doJobExecutions(final JobOperator jobOperator, final Exchange exchange, final String[] paths) throws Exception { final Message in = exchange.getIn(); if (paths.length == 1) { //urls like jberet:jobexecutions throw JBeretCamelMessages.MESSAGES.invalidJBeretComponentUri(Arrays.toString(paths)); } else if (paths.length == 2) { if (RUNNING.equals(paths[1])) { //urls like jberet:jobexecutions/running?jobName=job1 String jobName = ((JBeretEndpoint) getEndpoint()).getJobName(); if (jobName == null) { jobName = "*"; } in.setBody(jobOperator.getRunningExecutions(jobName), List.class); } else { //urls like jberet:jobexecutions/123456 long jobExecutionId = Long.parseLong(paths[1]); in.setBody(jobOperator.getJobExecution(jobExecutionId), JobExecution.class); } } else if (paths.length == 3) { long jobExecutionId = Long.parseLong(paths[1]); final String resourceOperation = paths[2]; if (STOP.equals(resourceOperation)) { //urls like jberet:jobexecutions/123456/stop jobOperator.stop(jobExecutionId); } else if (RESTART.equals(resourceOperation)) { //urls like jberet:jobexecutions/123456/restart in.setBody(jobOperator.restart(jobExecutionId, (Properties) in.getBody()), long.class); } else if (ABANDON.equals(resourceOperation)) { //urls like jberet:jobexecutions/123456/abandon jobOperator.abandon(jobExecutionId); } else { throw JBeretCamelMessages.MESSAGES.invalidJBeretComponentUri(Arrays.toString(paths)); } } } }