001/*
002 * (C) Copyright 2006-2007 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 *     Nuxeo - initial API and implementation
018 *
019 * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $
020 */
021
022package org.nuxeo.ecm.platform.ui.web.restAPI;
023
024import javax.faces.event.PhaseId;
025import javax.servlet.http.HttpServletRequest;
026
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.jboss.seam.contexts.FacesLifecycle;
030import org.jboss.seam.contexts.Lifecycle;
031import org.jboss.seam.contexts.ServletLifecycle;
032import org.jboss.seam.core.ConversationPropagation;
033import org.jboss.seam.core.Manager;
034import org.jboss.seam.servlet.ServletRequestSessionMap;
035import org.jboss.seam.web.ServletContexts;
036import org.nuxeo.ecm.platform.ui.web.util.SeamComponentCallHelper;
037import org.nuxeo.runtime.transaction.TransactionHelper;
038import org.restlet.Request;
039import org.restlet.Response;
040import org.restlet.Restlet;
041import org.restlet.data.MediaType;
042import org.restlet.data.Status;
043import org.restlet.engine.adapter.HttpRequest;
044import org.restlet.engine.adapter.ServerCall;
045import org.restlet.ext.servlet.internal.ServletCall;
046import org.restlet.routing.Filter;
047
048/**
049 * Restlet Filter to initialized Seam context
050 *
051 * @author <a href="mailto:td@nuxeo.com">Thierry Delprat</a>
052 * @author Florent Guillaume
053 */
054public class SeamRestletFilter extends Filter {
055
056    private static final Log log = LogFactory.getLog(SeamRestletFilter.class);
057
058    private boolean useConversation = false;
059
060    public SeamRestletFilter() {
061        this(false);
062    }
063
064    public SeamRestletFilter(boolean needConversation) {
065        useConversation = needConversation;
066    }
067
068    @Override
069    protected int beforeHandle(Request request, Response response) {
070        FacesLifecycle.setPhaseId(PhaseId.INVOKE_APPLICATION);
071        if (useConversation && (request instanceof HttpRequest)) {
072            // Complete HTTP call with conversation
073            ServerCall httpCall = ((HttpRequest) request).getHttpCall();
074            if (httpCall instanceof ServletCall) {
075                HttpServletRequest httpServletRequest = ((ServletCall) httpCall).getRequest();
076
077                // see ContextualHttpServletRequest / SOAPRequestHandler
078                ServletLifecycle.beginRequest(httpServletRequest);
079                ServletContexts.instance().setRequest(httpServletRequest);
080                ConversationPropagation.instance().restoreConversationId(httpServletRequest.getParameterMap());
081                Manager.instance().restoreConversation();
082                ServletLifecycle.resumeConversation(httpServletRequest);
083                Manager.instance().handleConversationPropagation(httpServletRequest.getParameterMap());
084                return CONTINUE;
085            }
086        }
087        // Standard call without conversation
088        Lifecycle.beginCall();
089        return CONTINUE;
090    }
091
092    @Override
093    protected void afterHandle(Request request, Response response) {
094        FacesLifecycle.setPhaseId(null);
095        if (useConversation && request instanceof HttpRequest) {
096            ServerCall httpCall = ((HttpRequest) request).getHttpCall();
097            if (httpCall instanceof ServletCall) {
098                if (TransactionHelper.isTransactionActive()) {
099                    // early commit of the transaction before releasing the
100                    // conversation lock to avoid a race condition on concurrent
101                    // access to the same documentManager instance by threads /
102                    // requests sharing the same conversation and triggering
103                    // StorageException "closed connection handle" on the RA
104                    // pool
105                    TransactionHelper.commitOrRollbackTransaction();
106                }
107                HttpServletRequest httpServletRequest = ((ServletCall) httpCall).getRequest();
108                // see ContextualHttpServletRequest / SOAPRequestHandler
109                Manager.instance().endRequest(new ServletRequestSessionMap(httpServletRequest));
110                ServletLifecycle.endRequest(httpServletRequest);
111                return;
112            }
113        }
114        Lifecycle.endCall();
115    }
116
117    @Override
118    protected int doHandle(Request request, Response response) {
119        if (getNext() != null) {
120            // get the Seam Wrapper from the instance
121            Restlet next = getNext();
122            Restlet seamRestlet = (Restlet) SeamComponentCallHelper.getSeamComponentByRef(next);
123            if (seamRestlet == null) {
124                final String errMsg = "Cannot get Seam component for restlet ";
125                log.error(errMsg + next);
126                response.setEntity(errMsg, MediaType.TEXT_PLAIN);
127            } else {
128                try {
129                    seamRestlet.handle(request, response);
130                } catch (RuntimeException e) {
131                    log.error("Restlet handling error", e);
132                    response.setEntity("Error while calling Seam aware Restlet: " + e.getMessage(),
133                            MediaType.TEXT_PLAIN);
134                }
135            }
136        } else {
137            response.setStatus(Status.CLIENT_ERROR_NOT_FOUND);
138        }
139        return CONTINUE;
140    }
141
142}