001/*
002 * (C) Copyright 2006-2011 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 *     Thierry Delprat
018 *     Florent Guillaume
019 */
020
021package org.nuxeo.ecm.platform.ui.web.restAPI;
022
023import java.io.IOException;
024
025import javax.servlet.ServletException;
026import javax.servlet.http.HttpServlet;
027import javax.servlet.http.HttpServletRequest;
028import javax.servlet.http.HttpServletResponse;
029
030import org.apache.commons.logging.Log;
031import org.apache.commons.logging.LogFactory;
032import org.nuxeo.ecm.platform.ui.web.restAPI.service.PluggableRestletService;
033import org.nuxeo.ecm.platform.ui.web.restAPI.service.RestletPluginDescriptor;
034import org.nuxeo.runtime.api.Framework;
035import org.nuxeo.runtime.transaction.TransactionHelper;
036import org.restlet.Filter;
037import org.restlet.Restlet;
038import org.restlet.Route;
039import org.restlet.Router;
040
041import com.noelios.restlet.ext.servlet.ServletConverter;
042
043/**
044 * Servlet used to run a Restlet inside Nuxeo.
045 * <p>
046 * Setup Seam Restlet filter if needed.
047 * <p>
048 * Ensures a transaction is started/committed.
049 */
050public class RestletServlet extends HttpServlet {
051
052    private static final Log log = LogFactory.getLog(RestletServlet.class);
053
054    private static final long serialVersionUID = 1764653653643L;
055
056    protected ServletConverter converter;
057
058    @Override
059    public synchronized void init() throws ServletException {
060        super.init();
061
062        converter = new ServletConverter(getServletContext());
063
064        // init the router
065        Router restletRouter = new Router();
066
067        // get the service
068        PluggableRestletService service = (PluggableRestletService) Framework.getRuntime().getComponent(
069                PluggableRestletService.NAME);
070        if (service == null) {
071            log.error("Unable to get Service " + PluggableRestletService.NAME);
072            throw new ServletException("Can't initialize Nuxeo Pluggable Restlet Service");
073        }
074
075        for (String restletName : service.getContributedRestletNames()) {
076            RestletPluginDescriptor plugin = service.getContributedRestletDescriptor(restletName);
077
078            Restlet restletToAdd;
079            if (plugin.getUseSeam()) {
080                Filter seamFilter = new SeamRestletFilter(plugin.getUseConversation());
081
082                Restlet seamRestlet = service.getContributedRestletByName(restletName);
083
084                seamFilter.setNext(seamRestlet);
085
086                restletToAdd = seamFilter;
087            } else {
088
089                if (plugin.isSingleton()) {
090                    restletToAdd = service.getContributedRestletByName(restletName);
091                } else {
092                    Filter threadSafeRestletFilter = new ThreadSafeRestletFilter();
093
094                    Restlet restlet = service.getContributedRestletByName(restletName);
095
096                    threadSafeRestletFilter.setNext(restlet);
097                    restletToAdd = threadSafeRestletFilter;
098                }
099            }
100
101            // force regexp init
102            for (String urlPattern : plugin.getUrlPatterns()) {
103                log.debug("Pre-compiling restlet pattern " + urlPattern);
104                Route route = restletRouter.attach(urlPattern, restletToAdd);
105                route.getTemplate().match("");
106            }
107        }
108
109        converter.setTarget(restletRouter);
110    }
111
112    @Override
113    protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
114        boolean tx = false;
115        if (!TransactionHelper.isTransactionActive()) {
116            tx = TransactionHelper.startTransaction();
117        }
118        try {
119            converter.service(req, res);
120        } catch (ServletException e) {
121            if (tx) {
122                TransactionHelper.setTransactionRollbackOnly();
123            }
124            throw e;
125        } catch (IOException e) {
126            if (tx) {
127                TransactionHelper.setTransactionRollbackOnly();
128            }
129            throw e;
130        } finally {
131            if (tx) {
132                if (TransactionHelper.isTransactionActiveOrMarkedRollback()) {
133                    // SeamRestletFilter might have done an early commit to
134                    // avoid race condition on the core session on restlets
135                    // who rely upon the conversation lock to fetch it
136                    // thread-safely
137                    TransactionHelper.commitOrRollbackTransaction();
138                }
139            }
140        }
141    }
142
143}