/**
* Copyright © 2013 enioka. All rights reserved
*
* 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.
*/
package com.enioka.jqm.api;
import java.io.InputStream;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.NotSupportedException;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The main web service class. Interface {@link JqmClient} is implemented, but it is not compulsory at all. (done for completion sake & and
* ease of update). Not all methods are exposed - some things are better left to the caller.
*/
@Path("/client")
public class ServiceClient implements JqmClient
{
static Logger log = LoggerFactory.getLogger(ServiceClient.class);
private @Context HttpServletResponse res;
// Not directly mapped: returning an integer would be weird. See enqueue_object.
public int enqueue(JobRequest jd)
{
throw new NotSupportedException();
}
@POST
@Path("ji")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public JobInstance enqueue_object(JobRequest jd)
{
int i = JqmClientFactory.getClient().enqueue(jd);
return getJi(jd, i);
}
// Not exposed. Client side work.
@Override
public int enqueue(String applicationName, String userName)
{
throw new NotSupportedException();
}
@Override
@Path("ji/{id}")
@POST
public int enqueueFromHistory(@PathParam("id") int jobIdToCopy)
{
return JqmClientFactory.getClient().enqueueFromHistory(jobIdToCopy);
}
@Override
@Path("ji/cancelled/{jobId}")
@POST
public void cancelJob(@PathParam("jobId") int jobId)
{
JqmClientFactory.getClient().cancelJob(jobId);
}
@Override
@Path("ji/waiting/{jobId}")
@DELETE
public void deleteJob(@PathParam("jobId") int jobId)
{
JqmClientFactory.getClient().deleteJob(jobId);
}
@Override
@Path("ji/killed/{jobId}")
@POST
public void killJob(@PathParam("jobId") int jobId)
{
JqmClientFactory.getClient().killJob(jobId);
}
@Override
@Path("ji/paused/{jobId}")
@POST
public void pauseQueuedJob(@PathParam("jobId") int jobId)
{
JqmClientFactory.getClient().pauseQueuedJob(jobId);
}
@Override
@Path("ji/paused/{jobId}")
@DELETE
public void resumeJob(@PathParam("jobId") int jobId)
{
JqmClientFactory.getClient().resumeJob(jobId);
}
// Not exposed directly - we prefer objects to primitive types
public int restartCrashedJob(int jobId)
{
return 0;
}
@Path("ji/crashed/{jobId}")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@DELETE
public JobInstance restartCrashedJob_object(@PathParam("jobId") int jobId)
{
int i = JqmClientFactory.getClient().restartCrashedJob(jobId);
return getJob(i);
}
@Override
@Path("q/{queueId: [0-9]+}/{jobId: [0-9]+}")
@POST
public void setJobQueue(@PathParam("jobId") int jobId, @PathParam("queueId") int queueId)
{
JqmClientFactory.getClient().setJobQueue(jobId, queueId);
}
// No need to expose. Client side work.
@Override
public void setJobQueue(int jobId, Queue queue)
{
JqmClientFactory.getClient().setJobQueue(jobId, queue);
}
@Override
@POST
@Path("ji/{jobId}/position/{newPosition}")
public void setJobQueuePosition(@PathParam("jobId") int jobId, @PathParam("newPosition") int newPosition)
{
JqmClientFactory.getClient().setJobQueuePosition(jobId, newPosition);
}
@Override
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("ji/{jobId}")
@HttpCache("public, max-age=60")
public JobInstance getJob(@PathParam("jobId") int jobId)
{
return JqmClientFactory.getClient().getJob(jobId);
}
@Override
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("ji")
@HttpCache("public, max-age=60")
public List<JobInstance> getJobs()
{
return JqmClientFactory.getClient().getJobs();
}
@Override
@GET
@Path("ji/active")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@HttpCache("public, max-age=60")
public List<JobInstance> getActiveJobs()
{
return JqmClientFactory.getClient().getActiveJobs();
}
@Override
@Path("user/{username}/ji")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@GET
@HttpCache("public, max-age=60")
public List<JobInstance> getUserActiveJobs(@PathParam("username") String userName)
{
return JqmClientFactory.getClient().getUserActiveJobs(userName);
}
// Not exposed directly - the Query object passed as parameter actually contains results...
@Override
public List<JobInstance> getJobs(Query query)
{
return JqmClientFactory.getClient().getJobs(query);
}
@Path("ji/query")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@POST
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Query getJobsQuery(Query query)
{
query.run();
return query;
}
@Override
@Path("ji/{jobId}/messages")
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@HttpCache("public, max-age=60")
public List<String> getJobMessages(@PathParam("jobId") int jobId)
{
return JqmClientFactory.getClient().getJobMessages(jobId);
}
// Not exposed. Use getJob => progress
@Override
public int getJobProgress(int jobId)
{
throw new NotSupportedException();
}
@Override
@Path("ji/{jobId}/files")
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@HttpCache("public, max-age=60")
public List<Deliverable> getJobDeliverables(@PathParam("jobId") int jobId)
{
List<Deliverable> res = JqmClientFactory.getClient().getJobDeliverables(jobId);
return res;
}
// Not exposed. Returning a list of files is a joke anyway... Loop should be client-side.
@Override
public List<InputStream> getJobDeliverablesContent(int jobId)
{
throw new NotSupportedException();
}
@Override
@Path("ji/files")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces("application/octet-stream")
@POST
public InputStream getDeliverableContent(Deliverable file)
{
SelfDestructFileStream fs = (SelfDestructFileStream) JqmClientFactory.getClient().getDeliverableContent(file);
res.setHeader("Content-Disposition", "attachment; filename=" + fs.nameHint);
return fs;
}
@Override
@Path("ji/files/{id}")
@Produces("application/octet-stream")
@GET
public InputStream getDeliverableContent(@PathParam("id") int delId)
{
SelfDestructFileStream fs = (SelfDestructFileStream) JqmClientFactory.getClient().getDeliverableContent(delId);
res.setHeader("Content-Disposition", "attachment; filename=" + fs.nameHint);
return fs;
}
@Override
@Path("ji/{jobId}/stderr")
@Produces("application/octet-stream")
@GET
public InputStream getJobLogStdErr(@PathParam("jobId") int jobId)
{
SelfDestructFileStream fs = (SelfDestructFileStream) JqmClientFactory.getClient().getJobLogStdErr(jobId);
res.setHeader("Content-Disposition", "attachment; filename=" + fs.nameHint);
return fs;
}
@Override
@Path("ji/{jobId}/stdout")
@Produces("application/octet-stream")
@GET
public InputStream getJobLogStdOut(@PathParam("jobId") int jobId)
{
SelfDestructFileStream fs = (SelfDestructFileStream) JqmClientFactory.getClient().getJobLogStdOut(jobId);
res.setHeader("Content-Disposition", "attachment; filename=" + fs.nameHint);
return fs;
}
@Override
@Path("q")
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@HttpCache("public, max-age=60")
public List<Queue> getQueues()
{
return JqmClientFactory.getClient().getQueues();
}
@Override
public void dispose()
{
log.debug("calling WS dispose");
// Nothing to do.
}
private JobInstance getJi(JobRequest jd, int i)
{
JobInstance ji = new JobInstance();
ji.setId(i);
ji.setKeyword1(jd.getKeyword1());
ji.setKeyword2(jd.getKeyword2());
ji.setKeyword3(jd.getKeyword3());
ji.setParameters(jd.getParameters());
ji.setParent(jd.getParentID());
ji.setSessionID(jd.getSessionID());
ji.setState(State.SUBMITTED);
ji.setUser(jd.getUser());
ji.setPosition(Long.MAX_VALUE);
ji.setApplication(jd.getApplication());
return ji;
}
@Path("jd")
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override
@HttpCache("public, max-age=60")
public List<JobDef> getJobDefinitions()
{
return JqmClientFactory.getClient().getJobDefinitions();
}
@Path("jd/{applicationName}")
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override
@HttpCache("public, max-age=60")
public List<JobDef> getJobDefinitions(@PathParam("applicationName") String application)
{
return JqmClientFactory.getClient().getJobDefinitions(application);
}
@Path("ji/query")
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@HttpCache("public, max-age=3600")
public Query getEmptyQuery()
{
return Query.create();
}
@Path("jr")
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@HttpCache("public, max-age=3600")
public JobRequest getEmptyJobRequest()
{
return new JobRequest("appName", "rsapi user");
}
}