/* * Copyright (c) 2015-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.rest.resource; import java.net.URI; import java.util.List; import java.util.Map; import java.util.Properties; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import org.jberet.rest._private.RestAPIMessages; import org.jberet.rest.entity.JobEntity; import org.jberet.rest.entity.JobExecutionEntity; import org.jberet.rest.entity.JobInstanceEntity; import org.jberet.schedule.JobSchedule; import org.jberet.schedule.JobScheduleConfig; import org.jberet.schedule.JobScheduler; /** * REST resource class for batch job. This class supports job-related operations * such as starting by job XML name, restarting the latest job execution of a * job name (id), and listing currently known jobs. * * @since 1.3.0 */ @Path("jobs") @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public class JobResource { /** * Starts a new job execution for the specified {@code jobXmlName}. * Job parameters can be taken from query parameters, obtained from {@code uriInfo}, * or {@code jobParamsAsProps} as {@code java.util.Properties}, or both. * When extracting query parameters from {@code uriInfo}, only the first value of * each key is used. When a key exists in both query parameters and {@code props}, * the latter takes precedence. * * @param jobXmlName job xml name, which usually is the same as job id * @param uriInfo {@code javax.ws.rs.core.UriInfo} that contains query parameters and other info * @param jobParamsAsProps job parameters properties * * @return {@code javax.ws.rs.core.Response}, which includes response status and newly * started job execution of type {@link JobExecutionEntity} */ @Path("{jobXmlName}/start") @POST public Response start(final @PathParam("jobXmlName") String jobXmlName, final @Context UriInfo uriInfo, final Properties jobParamsAsProps) { JobExecutionEntity jobExecutionData = JobService.getInstance() .start(jobXmlName, jobParametersFromUriInfoAndProps(uriInfo, jobParamsAsProps)); final URI jobExecutionDataUri = uriInfo.getBaseUriBuilder().path(JobExecutionResource.class). path(String.valueOf(jobExecutionData.getExecutionId())). build(); jobExecutionData.setHref(jobExecutionDataUri.toString()); return Response.created(jobExecutionDataUri).entity(jobExecutionData).build(); } @Path("{jobXmlName}/schedule") @POST public JobSchedule schedule(final JobScheduleConfig scheduleConfig) { final JobScheduler jobScheduler = JobScheduler.getJobScheduler(); return jobScheduler.schedule(scheduleConfig); } /** * Restarts the most recent job execution of a job name/id, with optional restart * job parameters. * <p> * Job parameters can be taken from query parameters, obtained from {@code uriInfo}, * or {@code jobParamsAsProps} as {@code java.util.Properties}, or both. * When extracting query parameters from {@code uriInfo}, only the first value of * each key is used. When a key exists in both query parameters and {@code props}, * the latter takes precedence. * <p> * Job parameters in the previous job execution that is to be restarted will continue * to be used in the restart job execution. Job parameters (as query parameters or * {@code java.util.Properties}) in the current invocation will complement and * override any same-keyed job parameters. * * @param jobXmlName job name/id, whose most recent job execution will be restarted * @param uriInfo {@code javax.ws.rs.core.UriInfo} that contains additional query parameters and other info * @param jobParamsAsProps additional job parameters properties * * @return {@code org.jberet.rest.entity.JobExecutionEntity} for the new job execution * * @see #start(String, UriInfo, Properties) * @see JobExecutionResource#restart(long, UriInfo, Properties) */ @Path("{jobXmlName}/restart") @POST public JobExecutionEntity restart(final @PathParam("jobXmlName") String jobXmlName, final @Context UriInfo uriInfo, final Properties jobParamsAsProps) { final JobInstanceEntity[] jobInstances = JobService.getInstance().getJobInstances(jobXmlName, 0, 1); if (jobInstances.length > 0) { final long latestJobExecutionId = jobInstances[0].getLatestJobExecutionId(); final JobExecutionEntity jobExecutionEntity = JobService.getInstance().restart( latestJobExecutionId, JobResource.jobParametersFromUriInfoAndProps(uriInfo, jobParamsAsProps)); JobExecutionResource.setJobExecutionEntityHref(uriInfo, jobExecutionEntity); return jobExecutionEntity; } else { throw RestAPIMessages.MESSAGES.invalidQueryParamValue("jobXmlName", jobXmlName); } } /** * Gets all jobs known to the current batch runtime. * Note that historical jobs that are not currently loaded in the batch runtime * will not be included in the result. * * @return array of {@code org.jberet.rest.entity.JobEntity} known to the batch runtime */ @GET public JobEntity[] getJobs() { return JobService.getInstance().getJobs(); } /** * Combines the properties from query parameters in {@code uriInfo} with the * {@code java.util.Properties} object {@code props}. When extracting * query parameters from {@code uriInfo}, only the first value of each key is * used. When a key exists in both query parameters and {@code props}, the latter * takes precedence. * * @param uriInfo the {@code javax.ws.rs.core.UriInfo} to extract query parameters * @param props the {@code java.util.Properties} object * @return a combined {@code java.util.Properties} */ static Properties jobParametersFromUriInfoAndProps(final UriInfo uriInfo, final Properties props) { final MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters(true); if (queryParameters.isEmpty()) { return props; } final Properties p = new Properties(); for (final Map.Entry<String, List<String>> e : queryParameters.entrySet()) { p.setProperty(e.getKey(), e.getValue().get(0)); } if (props != null) { for (final String k : props.stringPropertyNames()) { p.setProperty(k, props.getProperty(k)); } } return p; } }