Package org.emrys.webosgi.core.runtime

Source Code of org.emrys.webosgi.core.runtime.WabServletContext$MergeEnumeration

package org.emrys.webosgi.core.runtime;

import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletException;

import org.apache.AnnotationProcessor;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.emrys.webosgi.common.util.FileUtil;
import org.emrys.webosgi.core.FwkActivator;
import org.emrys.webosgi.core.classloader.WabClassLoaderFactory;
import org.emrys.webosgi.core.internal.FwkRuntime;
import org.emrys.webosgi.core.jeeres.FilterDelegate;
import org.emrys.webosgi.core.jeeres.ListenerInfo;
import org.emrys.webosgi.core.jeeres.ServletDelegate;
import org.emrys.webosgi.core.jeeres.TaglibInfo;
import org.emrys.webosgi.core.service.IOSGiWebContainer;
import org.emrys.webosgi.core.service.IWABServletContext;
import org.emrys.webosgi.core.service.IWebApplication;
import org.emrys.webosgi.core.util.WebBundleUtil;
import org.osgi.framework.Bundle;

/**
* Bundle Servlet Context for each web application bundle. This ServletContext
* wrapped the original ServletContext delivered from external Server, and
* modified its some behaviors like resource loading, request dispatcher
* getting. etc.
*
* @author Leo Chang
* @version 2011-3-22
*/
public class WabServletContext implements IWABServletContext {
  /**
   * ServletContext Attributes buffer
   */
  private final Hashtable<String, Object> attributes = new Hashtable<String, Object>();
  /**
   * Later set parameters buffer
   */
  private final Hashtable<String, String> laterInitParameters = new Hashtable<String, String>();
  /**
   * Original global ServletContext
   */
  ServletContext globalContext = null;

  /**
   * Servlet Filters buffer
   */
  private List<FilterDelegate> filters;
  /**
   * Servlet Listeners buffer.
   */
  private List<ListenerInfo> listeners;
  /**
   * Servlets in this ServletContext
   */
  private List<ServletDelegate> servlets;
  /**
   * Taglibs
   */
  private List<TaglibInfo> taglibs;
  /**
   * OSGiWebContainer instance
   */
  private final IOSGiWebContainer webContainer;

  /**
   * indicating whether only use Global Servlet Context. If true, realating
   * method will directly delegate to globale ServletContext.
   */
  private boolean onlyUseGlobalContext = false;
  /**
   * Include Global Context mark.
   */
  private boolean includeGlobalContext = false;
  /**
   * Wellcome pages of this bundled ServletContext
   */
  private List<String> welcomPages;
  /**
   * Error pages of this bundled ServletContext
   */
  private Map<Integer, String> errPages;

  // The default session timeout be set 1800 seconds.
  private int timeout = 1800;
  private final Bundle wabundle;
  private final String wabCtxPath;
  private final boolean isWebHostBundle;
  private File webContentRoot;
  private IPath webContentRootPath;
  private boolean isActive;
  private final IWebApplication webApplication;

  public WabServletContext(IWebApplication webApplication) {
    this.webApplication = webApplication;
    this.webContainer = FwkActivator.getInstance().getJeeContainer();
    this.globalContext = webContainer.getServletContext();
    this.wabundle = webApplication.getWebBundle();
    this.wabCtxPath = webApplication.getWebContextPath();

    // Judge if this wab is a host application with the context path "/".
    this.isWebHostBundle = WebBundleUtil.isHostWebBundle(getBundle());// "/".equals(wabCtxPath);
    // Always force clean the web content directory once the servlet context
    // init. If no Web Content found, this WAB has no Web Resources.
    File tmpWebContentRoot = webApplication.findWebContentRoot(true);
    if (tmpWebContentRoot != null) {
      this.webContentRoot = tmpWebContentRoot;
      this.webContentRootPath = new Path(webContentRoot.getAbsolutePath());
    }
    initAttributes();
  }

  /**
   * Initialize attributes of this Servlet Context.
   */
  protected void initAttributes() {
    // copy interesting attribute to this attributes.
    /*
     * String names[] = { "org.apache.catalina.WELCOME_FILES",
     * "javax.servlet.context.tempdir", "org.apache.catalina.jsp_classpath",
     * "org.apache.catalina.resources" };
     */
    Enumeration en = globalContext.getAttributeNames();
    while (en.hasMoreElements()) {
      String name = (String) en.nextElement();
      attributes.put(name, globalContext.getAttribute(name));
    }

    // If OSGi embedded, tmp dir may located in OS's tmp dir, the complied
    // jsp classes can be deleted by OS at anytime, we create a tmp dir for
    // each web bundles under a root folder.
    Object osgiEmbeddedLauncher = FwkRuntime.getInstance()
        .getFrameworkAttribute(FwkRuntime.ATTR_FWK_OSGI_EMBEDDED);
    if (Boolean.TRUE.equals(osgiEmbeddedLauncher)) {
      File jspClassesDir = new File(FwkActivator.getInstance()
          .getComponentWorkspaceRoot(), ".tmp" + wabCtxPath);
      // Try to clear tmp dir at first.
      if (jspClassesDir.exists())
        FileUtil.deleteAllFile(jspClassesDir, null);
      jspClassesDir.mkdirs();
      attributes.put("javax.servlet.context.tempdir", jspClassesDir);
    }

    /*
     * Attributes from tomcat6
     * org.apache.AnnotationProcessor=org.apache.catalina
     * .util.DefaultAnnotationProcessor@5443
     * javax.servlet.context.tempdir=D:
     * \btools_sdk1000505\tomcat\work\Catalina\localhost\web
     * org.apache.catalina
     * .resources=org.apache.naming.resources.ProxyDirContext@54643
     * org.apache.catalina.WELCOME_FILES=[Ljava.lang.String;@481958
     * org.apache
     * .catalina.jsp_classpath=/D:/btools_sdk1000505/tomcat/webapps
     * /web/WEB-INF/classes/,...
     *
     * Attributes from weblogic10
     * javax.servlet.context.tempdir=D:/bea/user_projects
     * /domains/Leo_domain/
     * servers/AdminServer/tmp/_WL_user/web/7f9y4c/public
     * weblogic.servlet.WebAppComponentMBean
     * =weblogic.management.configuration
     * .WebAppComponentMBeanImpl@af1e71([Leo_domain
     * ]/Applications[web]/WebAppComponents[web]
     * weblogic.servlet.WebAppComponentRuntimeMBean
     * =weblogic.servlet.internal.WebAppRuntimeMBeanImpl@24e11c
     */

    // Clear server related attributes, this will discard some special
    // featrue of server of a
    // certain type.
    attributes.remove("weblogic.servlet.WebAppComponentMBean");
    attributes.remove("weblogic.servlet.WebAppComponentRuntimeMBean");
    // set AnnotationProcessor null, not support jsp servlet's annotation.
    // set org.apache.catalina.jsp_classpath as empty
    attributes.remove(AnnotationProcessor.class.getName());
    attributes.remove("org.apache.catalina.jsp_classpath");
  }

  public void setInitParameter(String name, String value) {
    // this.setAttribute(name, value);
    laterInitParameters.put(name, value);
  }

  public ServletContext getGlobalContext() {
    return globalContext;
  }

  public Bundle getBundle() {
    return wabundle;
  }

  public Object getAttribute(String name) {
    if (includeGlobalContext) {
      Object value = attributes.get(name);
      if (value == null)
        value = globalContext.getAttribute(name);
      return value;
    }
    if (onlyUseGlobalContext)
      return globalContext.getAttribute(name);
    return attributes.get(name);
  }

  public Enumeration getAttributeNames() {
    if (includeGlobalContext) {
      MergeEnumeration en = new MergeEnumeration(attributes.keys(),
          globalContext.getAttributeNames());
      return en;
    }
    if (onlyUseGlobalContext)
      return globalContext.getAttributeNames();

    return attributes.keys();
  }

  public ServletContext getContext(String uripath) {
    // Allow to switch to another bundled servlet context.
    IPath path = new Path(uripath);
    String seg1 = path.segment(0);
    IWABServletContext ctx = webContainer.getBundledServletContext(seg1);
    if (ctx != null)
      return ctx;

    return this;// globalContext.getContext(uripath);
  }

  public String getContextPath() {
    // If the framework launcher web application deployed as HOST
    // application in the JavaEE Server, the global context path if
    // empty striing. The following code adaptable under this situation.
    if (onlyUseGlobalContext || isHostBundle())
      return globalContext.getContextPath();
    else {
      return new Path(globalContext.getContextPath()).append(
          getWABContextPath()).toPortableString();
    }
  }

  public String getInitParameter(String name) {
    if (includeGlobalContext) {
      String value = laterInitParameters.get(name);
      if (value == null)
        value = globalContext.getInitParameter(name);
      return value;
    }

    if (onlyUseGlobalContext)
      return globalContext.getInitParameter(name);

    return laterInitParameters.get(name);
  }

  public Enumeration getInitParameterNames() {
    if (includeGlobalContext) {
      MergeEnumeration en = new MergeEnumeration(laterInitParameters
          .keys(), globalContext.getInitParameterNames());
      return en;
    }
    if (onlyUseGlobalContext)
      return globalContext.getInitParameterNames();
    return laterInitParameters.keys();
  }

  public int getMajorVersion() {
    return globalContext.getMajorVersion();
  }

  public String getMimeType(String file) {
    return globalContext.getMimeType(file);
  }

  public int getMinorVersion() {
    return globalContext.getMinorVersion();
  }

  public RequestDispatcher getNamedDispatcher(String name) {
    // FIXME: Named Dispatcher not implemented.
    return null;// globalContext.getNamedDispatcher(name);
  }

  public String getRealPath(String path) {
    File root = getWebContentRoot();
    if (root != null && root.exists()) {
      IPath tmpPath = new Path(root.getAbsolutePath());
      tmpPath = tmpPath.append(path);
      if (tmpPath.toFile().exists())
        return tmpPath.toPortableString();

      // if not any file exists, just append the path to the root path and
      // return it.
      return new Path(root.getAbsolutePath()).append(path)
          .toPortableString();
    } else {
      // if this servlet context has not real root in local file system.
      return null;
    }
  }

  public File getWebContentRoot() {
    return webContentRoot;
  }

  public RequestDispatcher getRequestDispatcher(String path) {
    // Dispathcer get from ServletContext, the given path is relative
    // to the context root, and if get from ServletRequest, it's relative to
    // the current servlet path of that request.
    // If is host web bundle ,not use prefix.
    return new BundledRequestDispatcher((isHostBundle() ? null
        : getWABContextPath()), path);
    // return globalContext.getRequestDispatcher(path);
  }

  public URL getResource(String path) throws MalformedURLException {
    // NOTE: Any need to check that the path prefix with this bundle's
    // context path. YES! Because jasper will reuse compiled .class file if
    // there servlet path is the same, we cann't remove the bundel prefix
    // before call japsr to process jsp file. This job is done below. Check
    // the first segement and remove this bundle's context path at first.

    // Case /thisWab_ctxPath/ format, remove the context path.
    String thisWabCtxPath = getWABContextPath();
    if (path.startsWith(thisWabCtxPath) && !thisWabCtxPath.equals("/")) {
      path = path.substring(thisWabCtxPath.length());
    }

    // If this wab bundle is the host JavaEE bridge application, the actual
    // web.xml is renamed as FwkRuntime.HOST_WEB_XML_NAME.
    if (path.equals("/WEB-INF/web.xml") && isHostBundle())
      path = "/WEB-INF/" + FwkRuntime.HOST_WEB_XML_NAME;

    File root = getWebContentRoot();
    if (root == null || !root.exists())
      return null;

    File f = null;
    IPath tmpPath = new Path(root.getAbsolutePath());
    tmpPath = tmpPath.append(path);
    f = tmpPath.toFile();
    if (f.exists())
      return f.toURI().toURL();
    else {
      // Search WebContext/WEB-INF/classes for resource.
      tmpPath = new Path(root.getAbsolutePath());
      tmpPath = tmpPath.append("/WEB-INF/classes").append(path);
      f = tmpPath.toFile();
      if (f.exists())
        return f.toURI().toURL();
    }

    return null;
  }

  public InputStream getResourceAsStream(String path) {
    try {
      URL url = getResource(path);
      if (url != null)
        return url.openStream();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  public Set getResourcePaths(String path) {
    if (path == null || path.length() == 0)
      throw new IllegalArgumentException(
          "The path cann't be null or empty for resource paths.");

    final Set<String> pathStrs = new HashSet<String>();
    if (webContentRootPath == null)
      return pathStrs;

    File root = getWebContentRoot();
    IPath p = new Path(root.getAbsolutePath());
    p = p.append(path);
    File f = p.toFile();
    if (f.exists() && f.isDirectory()) {
      File[] fileList = f.listFiles();
      for (int i = 0; i < fileList.length; i++) {
        String fileName = fileList[i].getName();
        // Make sure the path is start with a "/" and end with "/" if
        // this path is a
        // directory.
        IPath currentPath = FileUtil.makeRelativeTo(p.append(fileName),
            webContentRootPath).makeAbsolute();
        String resPathStr = currentPath.toPortableString();
        if (fileList[i].isDirectory() && !resPathStr.endsWith("/"))
          resPathStr = resPathStr + "/";

        pathStrs.add(resPathStr);
      }
    }

    return pathStrs;
  }

  public String getServerInfo() {
    if (includeGlobalContext) {
      return globalContext.getServerInfo()
          + "; WebOSGi JavaEE Container/1.0.0(Servlet2.5, Equinox OSGi[3.5.2.R35])";
    } else if (onlyUseGlobalContext)
      return globalContext.getServerInfo();
    else
      return "WebOSGi JavaEE Container/1.0.0(Servlet2.5, Equinox OSGi[3.5.2.R35]) & "
          + globalContext.getServerInfo();
  }

  public Servlet getServlet(String name) throws ServletException {
    if (name == null)
      return null;

    Collection<ServletDelegate> list = this.getServletsInfo();
    for (ServletDelegate info : list) {
      if (name.equals(info.name))
        return info.getServlet();
    }
    return null;
  }

  public String getServletContextName() {
    // FIXME: Get servlet context name form web.xml display-name element.
    if (onlyUseGlobalContext || isHostBundle())
      return globalContext.getServletContextName();
    else
      return getWABContextPath();
  }

  public Enumeration getServletNames() {
    final Iterator<ServletDelegate> it = getServletsInfo().iterator();
    return new Enumeration() {
      public boolean hasMoreElements() {
        return it.hasNext();
      }

      public Object nextElement() {
        if (it.hasNext())
          return it.next().name;
        return null;
      }
    };
  }

  public Enumeration getServlets() {
    final Iterator<ServletDelegate> it = getServletsInfo().iterator();
    return new Enumeration() {
      public boolean hasMoreElements() {
        return it.hasNext();
      }

      public Object nextElement() {
        if (it.hasNext()) {
          try {
            return it.next().getServlet();
          } catch (ServletException e) {
            e.printStackTrace();
          }
        }
        return null;
      }
    };
  }

  public void log(Exception exception, String msg) {
    globalContext.log(exception, msg);
  }

  public void log(String message, Throwable throwable) {
    globalContext.log(message, throwable);
  }

  public void log(String msg) {
    globalContext.log(msg);
  }

  public void removeAttribute(String name) {
    if (onlyUseGlobalContext)
      globalContext.removeAttribute(name);
    else if (includeGlobalContext) {
      setAttribute(name, null);
      globalContext.removeAttribute(name);
    } else {
      setAttribute(name, null);
    }
  }

  public void setAttribute(String name, Object object) {
    if (onlyUseGlobalContext)
      globalContext.setAttribute(name, object);
    else if (includeGlobalContext) {
      setAttribute0(name, object);
      globalContext.setAttribute(name, object);
    } else {
      setAttribute0(name, object);
    }

  }

  /**
   * @param name
   * @param object
   */
  private void setAttribute0(String name, Object object) {
    Object original = attributes.get(name);
    if (object == null)
      attributes.remove(name);
    else
      attributes.put(name, object);

    ServletContextAttributeEvent scab = new ServletContextAttributeEvent(
        this, name, object);
    int et = -1;
    if (object == null && original != null)
      et = ET_ATTR_REMOVED;
    else if (original != null && !object.equals(original))
      et = ET_ATTR_REPLACED;
    else if (original == null && object != null)
      et = ET_ATTR_ADDED;

    if (et != -1)
      webContainer.trigerContextAttrEvent(scab, this, et);
  }

  public Collection<FilterDelegate> getFilters() {
    if (filters == null)
      filters = new ArrayList<FilterDelegate>();
    return filters;
  }

  public List<TaglibInfo> getTaglibs() {
    if (taglibs == null)
      taglibs = new ArrayList<TaglibInfo>();
    return taglibs;
  }

  public Collection<ListenerInfo> getListeners() {
    if (listeners == null)
      listeners = new ArrayList<ListenerInfo>();
    return listeners;
  }

  public Collection<ServletDelegate> getServletsInfo() {
    if (servlets == null)
      servlets = new ArrayList<ServletDelegate>();
    return servlets;
  }

  public void switchState(int state) {
    switch (state) {
    case STATE_NORMAL: {
      onlyUseGlobalContext = false;
      includeGlobalContext = false;
      break;
    }
    case STATE_INCLUE_GLOBAL_CTX: {
      onlyUseGlobalContext = false;
      includeGlobalContext = true;
      break;
    }
    case STATE_ONLY_USE_GLOBAL_CTX: {
      onlyUseGlobalContext = true;
      includeGlobalContext = false;
      break;
    }
    default: {
      onlyUseGlobalContext = false;
      includeGlobalContext = false;
    }
    }
  }

  class MergeEnumeration implements Enumeration {
    private final Enumeration e1;
    private final Enumeration e2;

    public MergeEnumeration(Enumeration e1, Enumeration e2) {
      this.e1 = e1;
      this.e2 = e2;
    }

    public boolean hasMoreElements() {
      return e1.hasMoreElements() || e2.hasMoreElements();
    }

    public Object nextElement() {
      if (e1.hasMoreElements())
        return e1.nextElement();
      if (e2.hasMoreElements())
        return e2.nextElement();
      return null;
    }
  }

  public Map<Integer, String> getErrorPages() {
    if (errPages == null)
      errPages = new HashMap<Integer, String>();
    return errPages;
  }

  public List<String> getWelcomePages() {
    if (welcomPages == null)
      welcomPages = new ArrayList<String>();
    return welcomPages;
  }

  public int getSessionTimeout() {
    return timeout;
  }

  public void setSessionTimeout(int interval) {
    timeout = interval;
  }

  public boolean isHostBundle() {
    return isWebHostBundle;
  }

  public String getWABContextPath() {
    return this.wabCtxPath;
  }

  public ClassLoader getWabClassLoader() {
    return WabClassLoaderFactory.getWabClassLoader(this);
  }

  public boolean isJspResource(String path) {
    return path.endsWith(".jsp");
  }

  public boolean isStaticResource(String path) {
    return true;
  }

  public void actived() {
    // do nothing by default.
  }

  public boolean isActive() {
    return isActive;
  }

  public void setActive(boolean b) {
    isActive = b;
  }

  public IWebApplication getWebApplication() {
    return webApplication;
  }
}
TOP

Related Classes of org.emrys.webosgi.core.runtime.WabServletContext$MergeEnumeration

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.