001/*
002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     dmetzler
016 */
017package org.nuxeo.ecm.restapi.server.jaxrs.adapters;
018
019import javax.servlet.http.HttpServletRequest;
020import javax.ws.rs.POST;
021import javax.ws.rs.Path;
022import javax.ws.rs.PathParam;
023import javax.ws.rs.Produces;
024import javax.ws.rs.core.Context;
025import javax.ws.rs.core.MediaType;
026import javax.ws.rs.core.Response;
027
028import org.nuxeo.ecm.automation.AutomationService;
029import org.nuxeo.ecm.automation.OperationChain;
030import org.nuxeo.ecm.automation.OperationContext;
031import org.nuxeo.ecm.automation.OperationException;
032import org.nuxeo.ecm.automation.OperationType;
033import org.nuxeo.ecm.automation.core.impl.ChainTypeImpl;
034import org.nuxeo.ecm.automation.core.impl.InvokableMethod;
035import org.nuxeo.ecm.automation.jaxrs.io.operations.ExecutionRequest;
036import org.nuxeo.ecm.automation.server.AutomationServer;
037import org.nuxeo.ecm.automation.server.jaxrs.ResponseHelper;
038import org.nuxeo.ecm.automation.server.jaxrs.RestOperationException;
039import org.nuxeo.ecm.platform.web.common.exceptionhandling.ExceptionHelper;
040import org.nuxeo.ecm.webengine.WebException;
041import org.nuxeo.ecm.webengine.model.WebAdapter;
042import org.nuxeo.ecm.webengine.model.impl.DefaultAdapter;
043import org.nuxeo.runtime.api.Framework;
044
045/**
046 * @since 5.7.2 - Web adapter that expose how to run an operation on a document
047 */
048@WebAdapter(name = OperationAdapter.NAME, type = "OperationService")
049@Produces({ "application/json+nxentity", "application/json+esentity", MediaType.APPLICATION_JSON })
050public class OperationAdapter extends DefaultAdapter {
051
052    public static final String NAME = "op";
053
054    @POST
055    @Path("{operationName}")
056    public Response doPost(@PathParam("operationName") String oid, @Context HttpServletRequest request,
057            ExecutionRequest xreq) {
058        try {
059            AutomationServer srv = Framework.getLocalService(AutomationServer.class);
060            if (!srv.accept(oid, false, request)) {
061                return ResponseHelper.notFound();
062            }
063
064            AutomationService service = Framework.getLocalService(AutomationService.class);
065
066            OperationType operationType = service.getOperation(oid);
067
068            // If chain, taking the first operation to do the input lookup after
069            if (operationType instanceof ChainTypeImpl) {
070                OperationChain chain = ((ChainTypeImpl) operationType).getChain();
071                if (!chain.getOperations().isEmpty()) {
072                    operationType = service.getOperation(chain.getOperations().get(0).id());
073                } else {
074                    throw new WebException("Chain '" + oid + "' doesn't contain any operation");
075                }
076            }
077
078            for (InvokableMethod method : operationType.getMethods()) {
079                if (getTarget().getAdapter(method.getInputType()) != null) {
080                    xreq.setInput(getTarget().getAdapter(method.getInputType()));
081                    break;
082                }
083            }
084
085            OperationContext ctx = xreq.createContext(request, getContext().getCoreSession());
086            Object result = service.run(ctx, oid, xreq.getParams());
087
088            int customHttpStatus = xreq.getRestOperationContext().getHttpStatus();
089            if (customHttpStatus >= 100) {
090                return Response.status(customHttpStatus).entity(result).build();
091            }
092
093            return Response.ok(result).build();
094        } catch (OperationException cause) {
095            if (ExceptionHelper.unwrapException(cause) instanceof RestOperationException) {
096                int customHttpStatus = ((RestOperationException) ExceptionHelper.unwrapException(cause)).getStatus();
097                throw WebException.newException("Failed to invoke operation: " + oid, cause, customHttpStatus);
098            }
099            throw WebException.newException("Failed to invoke operation: " + oid, cause);
100        }
101
102    }
103
104}