/FileExtraction/Java_unseen/dlitz_resin/modules/resin/src/com/caucho/server/webapp/ServletContextImpl.java
/*
 * 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 + "]";
  }
}

