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