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.Restlet;
037import org.restlet.ext.servlet.ServletAdapter;
038import org.restlet.routing.Filter;
039import org.restlet.routing.Router;
040import org.restlet.routing.Template;
041
042/**
043 * Servlet used to run a Restlet inside Nuxeo.
044 * <p>
045 * Setup Seam Restlet filter if needed.
046 * <p>
047 * Ensures a transaction is started/committed.
048 */
049public class RestletServlet extends HttpServlet {
050
051    private static final Log log = LogFactory.getLog(RestletServlet.class);
052
053    private static final long serialVersionUID = 1764653653643L;
054
055    protected ServletAdapter adapter;
056
057    @Override
058    public synchronized void init() throws ServletException {
059        super.init();
060
061        adapter = new ServletAdapter(getServletContext());
062
063        // init the router
064        Router restletRouter = new Router();
065
066        // get the service
067        PluggableRestletService service = (PluggableRestletService) Framework.getRuntime().getComponent(
068                PluggableRestletService.NAME);
069        if (service == null) {
070            log.error("Unable to get Service " + PluggableRestletService.NAME);
071            throw new ServletException("Can't initialize Nuxeo Pluggable Restlet Service");
072        }
073
074        for (String restletName : service.getContributedRestletNames()) {
075            RestletPluginDescriptor plugin = service.getContributedRestletDescriptor(restletName);
076
077            Restlet restletToAdd;
078            if (plugin.getUseSeam()) {
079                Filter seamFilter = new SeamRestletFilter(plugin.getUseConversation());
080
081                Restlet seamRestlet = service.getContributedRestletByName(restletName);
082
083                seamFilter.setNext(seamRestlet);
084
085                restletToAdd = seamFilter;
086            } else {
087
088                if (plugin.isSingleton()) {
089                    restletToAdd = service.getContributedRestletByName(restletName);
090                } else {
091                    Filter threadSafeRestletFilter = new ThreadSafeRestletFilter();
092
093                    Restlet restlet = service.getContributedRestletByName(restletName);
094
095                    threadSafeRestletFilter.setNext(restlet);
096                    restletToAdd = threadSafeRestletFilter;
097                }
098            }
099
100            for (String urlPattern : plugin.getUrlPatterns()) {
101                restletRouter.attach(urlPattern, restletToAdd, Template.MODE_STARTS_WITH);
102            }
103        }
104
105        adapter.setNext(restletRouter);
106    }
107
108    @Override
109    protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
110        boolean tx = false;
111        if (!TransactionHelper.isTransactionActive()) {
112            tx = TransactionHelper.startTransaction();
113        }
114        boolean ok = false;
115        try {
116            adapter.service(req, res);
117            ok = true;
118        } finally {
119            if (!ok) {
120                TransactionHelper.setTransactionRollbackOnly();
121            }
122            if (tx) {
123                if (TransactionHelper.isTransactionActiveOrMarkedRollback()) {
124                    // SeamRestletFilter might have done an early commit to
125                    // avoid race condition on the core session on restlets
126                    // who rely upon the conversation lock to fetch it
127                    // thread-safely
128                    TransactionHelper.commitOrRollbackTransaction();
129                }
130            }
131        }
132    }
133
134}