/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * bstefanescu */ package org.eclipse.ecr.web.jaxrs.servlet.config; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import org.eclipse.ecr.web.jaxrs.Activator; import org.eclipse.ecr.web.jaxrs.servlet.ServletHolder; import org.osgi.framework.Bundle; import org.osgi.service.http.HttpService; /** * Handle servlet registration from Nuxeo extension points. This class is a * singleton shared by the {@link Activator} and the * {@link ServletRegistryComponent} component. Because we don't have yet a * solution to synchronize the initialization time of the Activator and a Nuxeo * component we are using a singleton instance to be able * * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ public class ServletRegistry { public static final String SERVLET_NAME = ServletRegistry.class.getName()+".name"; private static volatile ServletRegistry instance; public static ServletRegistry getInstance() { ServletRegistry reg = instance; if (reg == null) { synchronized (ServletRegistry.class) { reg = new ServletRegistry(); instance = reg; } } return reg; } public static synchronized void dispose() { instance = null; } /** * Servlets contributed to the extension points. * Servlets are contributed to the {@link HttpService} when it becomes available. */ protected List<ServletDescriptor> servlets; protected List<FilterSetDescriptor> filters; /** * Store resources contributed from external bundles to servlets. * Map the servlet path to the list of contributed resources */ protected Map<String, List<ResourcesDescriptor>> resources; /** * The registered HttpContext mapped to the servlet path. * An HttpContext is created and inserted in this map when its servlet * is registered against the HttpService. * The context is removed when the servlet is unregsitered. * <p> * Resource contributions are injected into the context and reinjected each time the * context is restarted. */ protected Map<String, BundleHttpContext> contexts; /** * The HttpService instance is injected when the service becomes * available by the Activator. */ protected HttpService service; /** * The bundle owning this class */ protected Bundle bundle; private ServletRegistry() { this.servlets = new ArrayList<ServletDescriptor>(); this.filters = new ArrayList<FilterSetDescriptor>(); this.resources = new HashMap<String, List<ResourcesDescriptor>>(); this.contexts = new HashMap<String, BundleHttpContext>(); } public synchronized ServletDescriptor[] getServletDescriptors() { return servlets.toArray(new ServletDescriptor[servlets.size()]); } public synchronized FilterSetDescriptor[] getFilterSetDescriptors() { return filters.toArray(new FilterSetDescriptor[filters.size()]); } public ServletDescriptor getServletDescriptor(String name) { for (ServletDescriptor servlet : getServletDescriptors()) { if (name.equals(servlet.name)) { return servlet; } } return null; } public List<FilterSetDescriptor> getFiltersFor(String name) { ArrayList<FilterSetDescriptor> list = new ArrayList<FilterSetDescriptor>(); for (FilterSetDescriptor filter : getFilterSetDescriptors()) { if (name.equals(filter.targetServlet)) { list.add(filter); } } return list; } /** * Called by the service tracker when HttpService is up to configure it * with current contributed servlets * @param service */ public synchronized void initHttpService(HttpService service) throws Exception { if (this.service == null) { this.service = service; installServlets(); } } public HttpService getHttpService() { return service; } public synchronized void addServlet(ServletDescriptor descriptor) throws Exception { servlets.add(descriptor); installServlet(descriptor); } public synchronized void removeServlet(ServletDescriptor descriptor) { servlets.remove(descriptor); contexts.remove(descriptor.path); if (service != null) { // destroy first the listeners if any was initialized ListenerSetDescriptor lsd = descriptor.getListenerSet(); if (lsd != null) { lsd.destroy(); } // unregister the servlet service.unregister(descriptor.path); } } public synchronized void reloadServlet(ServletDescriptor descriptor) throws Exception { removeServlet(descriptor); addServlet(descriptor); } public synchronized void addFilterSet(FilterSetDescriptor filter) { filters.add(filter); } public synchronized void removeFilterSet(FilterSetDescriptor filter) { filters.remove(filter); } public synchronized void addResources(ResourcesDescriptor rd) { List<ResourcesDescriptor> list = resources.get(rd.getServlet()); if (list == null) { list = new ArrayList<ResourcesDescriptor>(); } list.add(rd); // update context BundleHttpContext ctx = contexts.get(rd.getServlet()); if (ctx != null) { ctx.setResources(list.toArray(new ResourcesDescriptor[list.size()])); } } public synchronized void removeResources(ResourcesDescriptor rd) { List<ResourcesDescriptor> list = resources.get(rd.getServlet()); if (list != null) { if (list.remove(rd)) { if (list.isEmpty()) { resources.remove(rd.getServlet()); } // update context BundleHttpContext ctx = contexts.get(rd.getServlet()); if (ctx != null) { ctx.setResources(list.toArray(new ResourcesDescriptor[list.size()])); } } } } private synchronized void installServlets() throws Exception { if (service != null) { for (ServletDescriptor sd : servlets) { installServlet(sd); } } } private void installServlet(ServletDescriptor sd) throws Exception { if (service != null) { //ClassRef ref = sd.getClassRef(); BundleHttpContext ctx = new BundleHttpContext(sd.bundle, sd.resources); List<ResourcesDescriptor> rd = resources.get(sd.path); // register resources contributed so far if (rd != null) { ctx.setResources(rd.toArray(new ResourcesDescriptor[rd.size()])); } Hashtable<String, String> params = new Hashtable<String, String>(); if (sd.name != null) { params.put(SERVLET_NAME, sd.name); } service.registerServlet(sd.path, new ServletHolder(), params, ctx); contexts.put(sd.path, ctx); } } // static class BundleHttpContext implements HttpContext { // protected Bundle bundle; // public BundleHttpContext(Bundle bundle) { // this.bundle = bundle; // } // @Override // public String getMimeType(String name) { // return null; // } // @Override // public URL getResource(String name) { // return null; // } // @Override // public boolean handleSecurity(HttpServletRequest request, // HttpServletResponse response) throws IOException { // // default behaviour assumes the container has already performed authentication // return true; // } // } }