blob: cf0d8741a25485d54c79c2b04c7de974fc266fd0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005-2007 Cognos Incorporated, IBM Corporation 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:
* Cognos Incorporated - initial API and implementation
* IBM Corporation - bug fixes and enhancements
*******************************************************************************/
package org.eclipse.equinox.http.servlet.internal;
import java.io.IOException;
import java.security.AccessController;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.osgi.framework.Bundle;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.NamespaceException;
/**
* The ProxyServlet is the private side of a Servlet that when registered (and init() called) in a servlet container
* will in-turn register and provide an OSGi Http Service implementation.
* This class is not meant for extending or even using directly and is purely meant for registering
* in a servlet container.
*/
public class ProxyServlet extends HttpServlet {
private static final long serialVersionUID = 4117456123807468871L;
private Map registrations = new HashMap(); //alias --> registration
private Set servlets = new HashSet(); //All the servlets objects that have been registered
private ProxyContext proxyContext;
public void init(ServletConfig config) throws ServletException {
super.init(config);
proxyContext = new ProxyContext(config.getServletContext());
Activator.addProxyServlet(this);
}
public void destroy() {
Activator.removeProxyServlet(this);
proxyContext.destroy();
proxyContext = null;
super.destroy();
}
/**
* @see HttpServlet#service(ServletRequest, ServletResponse)
*/
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
proxyContext.initializeServletPath(req);
String alias = HttpServletRequestAdaptor.getDispatchPathInfo(req);
if (alias == null)
alias = "/"; //$NON-NLS-1$
// perfect match
if (processAlias(req, resp, alias, null))
return;
String extensionAlias = findExtensionAlias(alias);
alias = alias.substring(0, alias.lastIndexOf('/'));
// longest path match
while (alias.length() != 0) {
if (processAlias(req, resp, alias, extensionAlias))
return;
alias = alias.substring(0, alias.lastIndexOf('/'));
}
// default handler match
if (extensionAlias != null)
extensionAlias = extensionAlias.substring(1); // remove the leading '/'
if (processAlias(req, resp, "/", extensionAlias)) //Handle '/' aliases //$NON-NLS-1$
return;
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "ProxyServlet: " + req.getRequestURI()); //$NON-NLS-1$
}
private String findExtensionAlias(String alias) {
String lastSegment = alias.substring(alias.lastIndexOf('/') + 1);
int dot = lastSegment.indexOf('.');
if (dot == -1)
return null;
String extension = lastSegment.substring(dot + 1);
if (extension.length() == 0)
return null;
return "/*." + extension; //$NON-NLS-1$
}
private boolean processAlias(HttpServletRequest req, HttpServletResponse resp, String alias, String extensionAlias) throws ServletException, IOException {
Registration registration = null;
synchronized (this) {
if (extensionAlias == null)
registration = (Registration) registrations.get(alias);
else {
registration = (Registration) registrations.get(alias + extensionAlias);
if (registration != null) // extensions should be handled on the full alias
alias = HttpServletRequestAdaptor.getDispatchPathInfo(req);
else
registration = (Registration) registrations.get(alias);
}
if (registration != null)
registration.addReference();
}
if (registration != null) {
try {
if (registration.handleRequest(req, resp, alias))
return true;
} finally {
registration.removeReference();
}
}
return false;
}
//Effective unregistration of servlet and resources as defined in HttpService#unregister()
synchronized void unregister(String alias, boolean destroy) {
Registration removedRegistration = (Registration) registrations.remove(alias);
if (removedRegistration != null) {
if (destroy)
removedRegistration.destroy();
removedRegistration.close();
}
}
//Effective registration of the servlet as defined HttpService#registerServlet()
synchronized void registerServlet(String alias, Servlet servlet, Dictionary initparams, HttpContext context, Bundle bundle) throws ServletException, NamespaceException {
checkAlias(alias);
if (servlet == null)
throw new IllegalArgumentException("Servlet cannot be null"); //$NON-NLS-1$
ServletRegistration registration = new ServletRegistration(servlet, proxyContext, context, bundle, servlets);
registration.checkServletRegistration();
ServletContext wrappedServletContext = new ServletContextAdaptor(proxyContext, getServletContext(), context, AccessController.getContext());
ServletConfig servletConfig = new ServletConfigImpl(servlet, initparams, wrappedServletContext);
registration.init(servletConfig);
registrations.put(alias, registration);
}
//Effective registration of the resources as defined HttpService#registerResources()
synchronized void registerResources(String alias, String name, HttpContext context) throws NamespaceException {
checkAlias(alias);
checkName(name);
registrations.put(alias, new ResourceRegistration(name, context, getServletContext(), AccessController.getContext()));
}
private void checkName(String name) {
if (name == null)
throw new IllegalArgumentException("Name cannot be null"); //$NON-NLS-1$
if (name.endsWith("/") && !name.equals("/")) //$NON-NLS-1$ //$NON-NLS-2$
throw new IllegalArgumentException("Invalid Name '" + name + "'"); //$NON-NLS-1$//$NON-NLS-2$
}
private void checkAlias(String alias) throws NamespaceException {
if (alias == null)
throw new IllegalArgumentException("Alias cannot be null"); //$NON-NLS-1$
if (!alias.startsWith("/") || (alias.endsWith("/") && !alias.equals("/"))) //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
throw new IllegalArgumentException("Invalid alias '" + alias + "'"); //$NON-NLS-1$//$NON-NLS-2$
if (registrations.containsKey(alias))
throw new NamespaceException("The alias '" + alias + "' is already in use."); //$NON-NLS-1$//$NON-NLS-2$
}
}