/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.server.webapp;
import com.caucho.VersionFactory;
import com.caucho.config.Configurable;
import com.caucho.util.L10N;
import com.caucho.vfs.Path;
import javax.servlet.*;
import javax.servlet.descriptor.JspConfigDescriptor;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Bare-bones servlet context implementation.
*/
public class ServletContextImpl extends ServletContextCompat
implements ServletContext
{
static final Logger log
= Logger.getLogger(ServletContextImpl.class.getName());
static final L10N L = new L10N(ServletContextImpl.class);
private String _name;
private HashMap<String,Object> _attributes = new HashMap<String,Object>();
private ArrayList<ServletContextAttributeListener>
_applicationAttributeListeners;
private HashMap<String,String> _initParams = new HashMap<String,String>();
public Path getRootDirectory()
{
throw new UnsupportedOperationException();
}
/**
* Sets the servlet context name
*/
public void setDisplayName(String name)
{
_name = name;
}
/**
* Gets the servlet context name
*/
public String getServletContextName()
{
return _name;
}
/**
* Gets the servlet context name
*/
public String getContextPath()
{
return _name;
}
/**
* Adds the listener.
*/
protected void addAttributeListener(ServletContextAttributeListener listener)
{
if (_applicationAttributeListeners == null)
_applicationAttributeListeners = new ArrayList<ServletContextAttributeListener>();
_applicationAttributeListeners.add(listener);
}
/**
* Returns the server information
*/
public String getServerInfo()
{
return "Resin/" + VersionFactory.getVersion();
}
/**
* Returns the servlet major version
*/
public int getMajorVersion()
{
return 3;
}
public int getEffectiveMajorVersion()
{
return 3;
}
/**
* Returns the servlet minor version
*/
public int getMinorVersion()
{
return 0;
}
public int getEffectiveMinorVersion()
{
return 0;
}
/**
* Sets an init param
*/
public boolean setInitParameter(String name, String value)
{
if (isActive())
throw new IllegalStateException(L.l("setInitParameter must be called before the web-app has been initialized, because it's required by the servlet spec."));
// server/1h12
if (_initParams.containsKey(name))
return false;
_initParams.put(name, value);
return true;
}
/**
* Sets an init param
*/
protected void setInitParam(String name, String value)
{
_initParams.put(name, value);
}
/**
* Gets the init params
*/
public String getInitParameter(String name)
{
return _initParams.get(name);
}
/**
* Gets the init params
*/
public Enumeration<String> getInitParameterNames()
{
return Collections.enumeration(_initParams.keySet());
}
/**
* Returns the named attribute.
*/
public Object getAttribute(String name)
{
synchronized (_attributes) {
Object value = _attributes.get(name);
return value;
}
}
/**
* Returns an enumeration of the attribute names.
*/
public Enumeration<String> getAttributeNames()
{
synchronized (_attributes) {
return Collections.enumeration(_attributes.keySet());
}
}
/**
* Sets an application attribute.
*
* @param name the name of the attribute
* @param value the value of the attribute
*/
public void setAttribute(String name, Object value)
{
Object oldValue;
synchronized (_attributes) {
if (value != null)
oldValue = _attributes.put(name, value);
else
oldValue = _attributes.remove(name);
}
// Call any listeners
if (_applicationAttributeListeners != null) {
ServletContextAttributeEvent event;
if (oldValue != null)
event = new ServletContextAttributeEvent(this, name, oldValue);
else
event = new ServletContextAttributeEvent(this, name, value);
for (int i = 0; i < _applicationAttributeListeners.size(); i++) {
ServletContextAttributeListener listener;
Object objListener = _applicationAttributeListeners.get(i);
listener = (ServletContextAttributeListener) objListener;
try {
if (oldValue != null)
listener.attributeReplaced(event);
else
listener.attributeAdded(event);
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
}
}
}
/**
* Removes an attribute from the servlet context.
*
* @param name the name of the attribute to remove.
*/
public void removeAttribute(String name)
{
Object oldValue;
synchronized (_attributes) {
oldValue = _attributes.remove(name);
}
// Call any listeners
if (_applicationAttributeListeners != null) {
ServletContextAttributeEvent event;
event = new ServletContextAttributeEvent(this, name, oldValue);
for (int i = 0; i < _applicationAttributeListeners.size(); i++) {
ServletContextAttributeListener listener;
Object objListener = _applicationAttributeListeners.get(i);
listener = (ServletContextAttributeListener) objListener;
try {
listener.attributeRemoved(event);
} catch (Throwable e) {
log.log(Level.FINE, e.toString(), e);
}
}
}
}
/**
* Maps from a URI to a real path.
*/
public String getRealPath(String uri)
{
return getRootDirectory().lookup("./" + uri).getNativePath();
}
/**
* Returns a resource for the given uri.
*
* <p>XXX: jdk 1.1.x doesn't appear to allow creation of private
* URL streams.
*/
@Override
public URL getResource(String name)
throws java.net.MalformedURLException
{
if (! name.startsWith("/"))
throw new java.net.MalformedURLException(name);
String realPath = getRealPath(name);
Path rootDirectory = getRootDirectory();
Path path = rootDirectory.lookupNative(realPath);
URL url = new URL("jndi:/server" + getContextPath() + name);
if (path.exists() && name.startsWith("/resources/")) {
return url;
}
else if (path.isFile()) {
return url;
}
else if (getClassLoader().getResource("META-INF/resources/" + realPath) != null) {
return url;
}
else if (path.exists()) {
return new URL(path.getURL());
}
return null;
}
public URLConnection getResource(URL url)
throws IOException
{
if (! "jndi".equals(url.getProtocol()))
return null;
//handle jndi:/server (single slash) parsing (gf)
String file = url.getFile();
if ("".equals(url.getHost()) && file.startsWith("/server")) {
file = file.substring(7, file.length());
if (file.startsWith(getContextPath()))
file = file.substring(getContextPath().length());
else {
// server/102p
int p = file.indexOf('/', 1);
if (p > 0) {
String contextPath = file.substring(0, p);
WebApp webApp = (WebApp) getContext(contextPath);
if (webApp != null)
return webApp.getResource(url);
}
}
}
String realPath = getRealPath(file);
Path rootDirectory = getRootDirectory();
Path path = rootDirectory.lookup(realPath);
if (path.exists())
return new URL(path.getURL()).openConnection();
int fileIdx;
URLConnection connection = null;
if (file.length() > 1 && (fileIdx = file.indexOf("/", 1)) > -1) {
String context = file.substring(0, file.indexOf("/", 1));
if (context.equals(getContextPath())) {// disable cross-context lookup
file = file.substring(fileIdx, file.length());
realPath = getRealPath(file);
path = rootDirectory.lookup(realPath);
if (path.exists())
connection = new URL(path.getURL()).openConnection();
}
}
if (connection != null)
return connection;
return new FileNotFoundURLConnection(url);
}
public Path getCauchoPath(String name)
{
String realPath = getRealPath(name);
Path rootDirectory = getRootDirectory();
Path path = rootDirectory.lookupNative(realPath);
return path;
}
/**
* Returns the resource for a uripath as an input stream.
*/
public InputStream getResourceAsStream(String uripath)
{
Path rootDirectory = getRootDirectory();
Path path = rootDirectory.lookupNative(getRealPath(uripath));
try {
if (path.canRead())
return path.openRead();
else {
String resource = "META-INF/resources" + uripath;
return getClassLoader().getResourceAsStream(resource);
}
} catch (IOException e) {
log.log(Level.FINEST, e.toString(), e);
return null;
}
}
/**
* Returns an enumeration of all the resources.
*/
public Set<String> getResourcePaths(String prefix)
{
if (! prefix.endsWith("/"))
prefix = prefix + "/";
Path path = getRootDirectory().lookup(getRealPath(prefix));
HashSet<String> set = new HashSet<String>();
try {
String []list = path.list();
for (int i = 0; i < list.length; i++) {
if (path.lookup(list[i]).isDirectory())
set.add(prefix + list[i] + '/');
else
set.add(prefix + list[i]);
}
} catch (IOException e) {
}
/*
try {
Enumeration<URL> paths = getClassLoader().getResources(resourceName);
while (paths.hasMoreElements()) {
URL subPath = paths.nextElement();
String subPathName = subPath.toString();
int p = subPathName.indexOf("META-INF/resources");
if (p >= 0)
set.add(subPathName.substring(p + "META-INF/resources".length()));
}
} catch (IOException e) {
log.log(Level.FINER, e.toString(), e);
}
*/
return set;
}
/**
* Returns the servlet context for the name.
*/
public ServletContext getContext(String uri)
{
return this;
}
/**
* Returns the mime type for the name.
*/
public String getMimeType(String uri)
{
return null;
}
/**
* Returns the dispatcher.
*/
public RequestDispatcher getRequestDispatcher(String uri)
{
return null;
}
/**
* Returns a dispatcher for the named servlet.
*/
public RequestDispatcher getNamedDispatcher(String servletName)
{
return null;
}
/**
* Logging.
*/
/**
* Logs a message to the error file.
*
* @param msg the message to log
*/
public final void log(String message)
{
log(message, null);
}
/**
* @deprecated
*/
public final void log(Exception e, String msg)
{
log(msg, e);
}
/**
* Error logging
*
* @param message message to log
* @param e stack trace of the error
*/
public void log(String message, Throwable e)
{
if (e != null)
log.log(Level.WARNING, message, e);
else
log.info(message);
}
//
// Deprecated methods
//
public Servlet getServlet(String name)
{
throw new UnsupportedOperationException("getServlet is deprecated");
}
public Enumeration<String> getServletNames()
{
throw new UnsupportedOperationException("getServletNames is deprecated");
}
public Enumeration<Servlet> getServlets()
{
throw new UnsupportedOperationException("getServlets is deprecated");
}
public void setSessionTrackingModes(Set<SessionTrackingMode> modes)
{
throw new UnsupportedOperationException("unimplemented");
}
public ServletRegistration.Dynamic addServlet(String servletName,
String className)
{
throw new UnsupportedOperationException("unimplemented");
}
public ServletRegistration.Dynamic addServlet(String servletName,
Servlet servlet)
{
throw new UnsupportedOperationException("unimplemented");
}
public ServletRegistration.Dynamic addServlet(String servletName,
Class<? extends Servlet> servletClass)
{
throw new UnsupportedOperationException("unimplemented");
}
public <T extends Servlet> T createServlet(Class<T> c)
throws ServletException
{
throw new UnsupportedOperationException("unimplemented");
}
public ServletRegistration getServletRegistration(String servletName)
{
throw new UnsupportedOperationException("unimplemented");
}
public Map<String, ServletRegistration> getServletRegistrations()
{
throw new UnsupportedOperationException("unimplemented");
}
public FilterRegistration.Dynamic addFilter(String filterName,
String className)
{
throw new UnsupportedOperationException("unimplemented");
}
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter)
{
throw new UnsupportedOperationException("unimplemented");
}
public FilterRegistration.Dynamic addFilter(String filterName,
Class<? extends Filter> filterClass)
{
throw new UnsupportedOperationException("unimplemented");
}
public <T extends Filter> T createFilter(Class<T> c)
throws ServletException
{
throw new UnsupportedOperationException("unimplemented");
}
public FilterRegistration getFilterRegistration(String filterName)
{
throw new UnsupportedOperationException("unimplemented");
}
/**
* Returns filter registrations
* @return
*/
@Override
public Map<String, ? extends FilterRegistration> getFilterRegistrations()
{
throw new UnsupportedOperationException("unimplemented");
}
@Configurable
public void addListener(ListenerConfig config)
throws Exception
{
}
public void addListener(String className)
{
throw new UnsupportedOperationException(getClass().getName());
}
public <T extends EventListener> void addListener(T t)
{
throw new UnsupportedOperationException(getClass().getName());
}
public void addListener(Class<? extends EventListener> listenerClass)
{
throw new UnsupportedOperationException(getClass().getName());
}
public JspConfigDescriptor getJspConfigDescriptor()
{
throw new UnsupportedOperationException(getClass().getName());
}
public ClassLoader getClassLoader()
{
throw new UnsupportedOperationException(getClass().getName());
}
public void declareRoles(String... roleNames)
{
throw new UnsupportedOperationException(getClass().getName());
}
protected boolean isActive()
{
throw new UnsupportedOperationException("unimplemented");
}
/* (non-Javadoc)
* @see javax.servlet.ServletContext#createListener(java.lang.Class)
*/
@Override
public <T extends EventListener> T createListener(Class<T> listenerClass)
throws ServletException
{
// TODO Auto-generated method stub
return null;
}
}
class FileNotFoundURLConnection extends URLConnection {
FileNotFoundURLConnection(URL url)
{
super(url);
}
@Override
public void connect()
throws IOException
{
}
@Override
public InputStream getInputStream()
throws IOException
{
throw new FileNotFoundException(url.toString());
}
@Override
public String toString()
{
return getClass().getSimpleName() + "[" + url + "]";
}
}