001/*
002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     dmetzler
018 */
019package org.nuxeo.ecm.restapi.server.jaxrs.adapters;
020
021import javax.servlet.http.HttpServletRequest;
022import javax.ws.rs.POST;
023import javax.ws.rs.Path;
024import javax.ws.rs.PathParam;
025import javax.ws.rs.Produces;
026import javax.ws.rs.core.Context;
027import javax.ws.rs.core.MediaType;
028import javax.ws.rs.core.Response;
029
030import org.nuxeo.ecm.automation.AutomationService;
031import org.nuxeo.ecm.automation.OperationChain;
032import org.nuxeo.ecm.automation.OperationContext;
033import org.nuxeo.ecm.automation.OperationException;
034import org.nuxeo.ecm.automation.OperationType;
035import org.nuxeo.ecm.automation.core.impl.ChainTypeImpl;
036import org.nuxeo.ecm.automation.core.impl.InvokableMethod;
037import org.nuxeo.ecm.automation.jaxrs.io.operations.ExecutionRequest;
038import org.nuxeo.ecm.automation.server.AutomationServer;
039import org.nuxeo.ecm.automation.server.jaxrs.ResponseHelper;
040import org.nuxeo.ecm.automation.server.jaxrs.RestOperationException;
041import org.nuxeo.ecm.platform.web.common.exceptionhandling.ExceptionHelper;
042import org.nuxeo.ecm.webengine.WebException;
043import org.nuxeo.ecm.webengine.model.WebAdapter;
044import org.nuxeo.ecm.webengine.model.impl.DefaultAdapter;
045import org.nuxeo.runtime.api.Framework;
046
047/**
048 * @since 5.7.2 - Web adapter that expose how to run an operation on a document
049 */
050@WebAdapter(name = OperationAdapter.NAME, type = "OperationService")
051@Produces({ "application/json+nxentity", "application/json+esentity", MediaType.APPLICATION_JSON })
052public class OperationAdapter extends DefaultAdapter {
053
054    public static final String NAME = "op";
055
056    @POST
057    @Path("{operationName}")
058    public Response doPost(@PathParam("operationName") String oid, @Context HttpServletRequest request,
059            ExecutionRequest xreq) {
060        try {
061            AutomationServer srv = Framework.getLocalService(AutomationServer.class);
062            if (!srv.accept(oid, false, request)) {
063                return ResponseHelper.notFound();
064            }
065
066            AutomationService service = Framework.getLocalService(AutomationService.class);
067
068            OperationType operationType = service.getOperation(oid);
069
070            // If chain, taking the first operation to do the input lookup after
071            if (operationType instanceof ChainTypeImpl) {
072                OperationChain chain = ((ChainTypeImpl) operationType).getChain();
073                if (!chain.getOperations().isEmpty()) {
074                    operationType = service.getOperation(chain.getOperations().get(0).id());
075                } else {
076                    throw new WebException("Chain '" + oid + "' doesn't contain any operation");
077                }
078            }
079
080            for (InvokableMethod method : operationType.getMethods()) {
081                if (getTarget().getAdapter(method.getInputType()) != null) {
082                    xreq.setInput(getTarget().getAdapter(method.getInputType()));
083                    break;
084                }
085            }
086
087            OperationContext ctx = xreq.createContext(request, getContext().getCoreSession());
088            Object result = service.run(ctx, oid, xreq.getParams());
089
090            int customHttpStatus = xreq.getRestOperationContext().getHttpStatus();
091            if (customHttpStatus >= 100) {
092                return Response.status(customHttpStatus).entity(result).build();
093            }
094
095            return Response.ok(result).build();
096        } catch (OperationException cause) {
097            if (ExceptionHelper.unwrapException(cause) instanceof RestOperationException) {
098                int customHttpStatus = ((RestOperationException) ExceptionHelper.unwrapException(cause)).getStatus();
099                throw WebException.newException("Failed to invoke operation: " + oid, cause, customHttpStatus);
100            }
101            throw WebException.newException("Failed to invoke operation: " + oid, cause);
102        }
103
104    }
105
106}