Package org.emrys.webosgi.core.runtime

Source Code of org.emrys.webosgi.core.runtime.WebApplication

/**
*
*/
package org.emrys.webosgi.core.runtime;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.emrys.webosgi.core.FwkActivator;
import org.emrys.webosgi.core.IFwkConstants;
import org.emrys.webosgi.core.ServiceInitException;
import org.emrys.webosgi.core.internal.FwkRuntime;
import org.emrys.webosgi.core.jeeres.FilterDelegate;
import org.emrys.webosgi.core.jeeres.FilterDelegateBase;
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;
import org.osgi.service.http.NamespaceException;

/**
* @author LeoChang
*
*/
public class WebApplication implements IWebApplication {

  private static IOSGiWebContainer webContainer = FwkActivator.getInstance()
      .getJeeContainer();
  private static FwkRuntime fwkRuntime = FwkRuntime.getInstance();

  private final Bundle bundle;
  private File webContentRoot;
  private IWABServletContext servletContext;
  private boolean isDynaServicesStarted;
  private String ctxPath;
  private boolean triedToStartFailed;

  public WebApplication(Bundle webbundle) {
    this.bundle = webbundle;
    String ctxPath = WebBundleUtil.getWabContextPathHeader(webbundle);
    if (StringUtils.isNotEmpty(ctxPath)) {
      if (!ctxPath.startsWith("/"))
        ctxPath = "/" + ctxPath;
      this.setWebContextPath(ctxPath);
    }
    // else check if this given bundle is a web bundle with context path.
  }

  public IOSGiWebContainer getWebContainer() {
    return webContainer;
  }

  public Bundle getWebBundle() {
    return bundle;
  }

  public File findWebContentRoot(boolean forceUpdate) {
    if (webContentRoot == null || forceUpdate) {
      try {
        webContentRoot = WebBundleUtil.getExtractedWebContentRoot(
            bundle, forceUpdate).toFile();
      } catch (IOException e) {
        // e.printStackTrace();
        log(e);
      }
    }
    return webContentRoot;
  }

  public IWABServletContext getBundleServletContext() {
    if (servletContext == null)
      servletContext = new WabServletContext(this);

    return servletContext;
  }

  public void setWebContextPath(String ctxPath) {
    this.ctxPath = ctxPath;
  }

  public String getWebContextPath() {
    String ctxPath = WebBundleUtil.getWabContextPathHeader(bundle);
    if (StringUtils.isNotEmpty(ctxPath))
      return ctxPath.startsWith("/") ? ctxPath : "/" + ctxPath;

    return this.ctxPath;
  }

  public void pubStaticResources() throws ServiceInitException {
    // Do nothing by default.
  }

  public boolean isStaticResPublished() {
    return true;
  }

  public void init() throws ServiceInitException {
    // Validate context path
    validateContextPath();

    // It need wab servlet context be registered to web container early for
    // resource publish.
    IWABServletContext servletContext = getBundleServletContext();
    try {
      if (!getWebContainer().getAllBundledServletContext().contains(
          servletContext)) {
        getWebContainer().regServletContext(servletContext);
      }
    } catch (Exception e) {
      throw new ServiceInitException(new Status(Status.ERROR, bundle
          .getSymbolicName(), "Web Service init failed.", e));
    }

    // Parse JavaEE Configuration to servlet context.
    // avoid dom4j using SAXParser provided from server
    /*
     * String externalSaxParser =
     * System.getProperty("javax.xml.parsers.SAXParserFactory"); // init
     * web.xml config all from other source.
     * System.setProperty("javax.xml.parsers.SAXParserFactory", null); try {
     * initWebConfig(); } finally {
     * System.setProperty("javax.xml.parsers.SAXParserFactory",
     * externalSaxParser); }
     */

    // Parse JavaEE Configure from web.xml if exists.
    initWebConfig();
  }

  public void startDynamicServices() throws ServiceInitException {
    if (!fwkRuntime.isFwkInited())
      throw new ServiceInitException(
          new Status(Status.ERROR, bundle.getSymbolicName(),
              "The web bundle cann't active before web container initiliazed."));

    synchronized (this) {
      // Only call once.
      if (!isDynaServicesStarted() && !triedToStartFailed) {
        // Enter app starting block.
        fwkRuntime.enterAppSvcStart(this);

        try {
          triedToStartFailed = true;
          // Start JavaEE service to wab servlet context. Now, the
          // bundle should be actived and bundle context is available.
          active();
          isDynaServicesStarted = true;

          log(new Status(Status.INFO, bundle.getSymbolicName(),
              "Web Service in bundle ID:"
                  + bundle.getSymbolicName() + " ["
                  + getWebContextPath() + "] published OK."));
        } catch (Throwable t) {
          // t.printStackTrace();
          webContainer.unregServletContext(servletContext);
          log(new Status(Status.ERROR, bundle.getSymbolicName(),
              "Web Service in Web bundle:"
                  + bundle.getSymbolicName() + " ["
                  + getWebContextPath()
                  + "] published Failed.", t));
        } finally {
          // Quit app starting block anyhow at last.
          fwkRuntime.quitAppSvcStart(this);
        }
      }
    }
  }

  public void stopDynamicServices() {
    // No need to deactive the servletContext here, the web container will
    // do this for use.
    this.getWebContainer().unregServletContext(servletContext);
    isDynaServicesStarted = false;
    servletContext = null;
  }

  public boolean isDynaServicesStarted() {
    return isDynaServicesStarted;
  }

  public void setDynaServicesStarted(boolean b) {
    this.isDynaServicesStarted = b;
  }

  protected void active() throws ServiceInitException {
    try {
      getWebContainer().activeServletContext(servletContext);
      initFilters();
      initOnStartServlet();
    } catch (Throwable t) {
      throw new ServiceInitException(new Status(Status.ERROR, bundle
          .getSymbolicName(), "Web Service init failed.", t));
    }
  }

  private void initFilters() throws ServletException {
    for (FilterDelegate f : servletContext.getFilters()) {
      try {
        f.init(null);
      } catch (Exception e) {
        throw new ServletException("Init servlet filter:"
            + f.getFilterName() + " failed.", e);
      }
    }
  }

  private void initOnStartServlet() throws ServletException {
    List<ServletDelegate> servlets = new ArrayList<ServletDelegate>();
    servlets.addAll(servletContext.getServletsInfo());
    Collections.sort(servlets, new Comparator() {
      public int compare(Object o1, Object o2) {
        ServletDelegate info1 = (ServletDelegate) o1;
        ServletDelegate info2 = (ServletDelegate) o2;
        if (info1.loadOnSetupPriority < info2.loadOnSetupPriority)
          return -1;
        else if (info1.loadOnSetupPriority > info2.loadOnSetupPriority)
          return 1;
        else
          return 0;
      }
    });

    for (ServletDelegate servletDelegate : servlets) {
      if (servletDelegate.loadOnSetupPriority > 0)
        servletDelegate.init(null);
    }
  }

  /**
   * Check the doubled service name space id in loaded web bundles.
   *
   * @throws ServiceInitException
   */
  private void validateContextPath() throws ServiceInitException {
    // check double named Name Space and its prefix.
  }

  /**
   * Default method to find web.xml file from web content directory.
   *
   * @return
   * @throws Exception
   */
  protected InputStream getWebXmlInput() throws Exception {
    // If this web bundle has not Web Content directory, not find any
    // web.xml.
    if (webContentRoot != null) {
      String webXmlFileName = "web.xml";
      // If this wab bundle is bridge web host bundle, use special
      // web.xml file name.
      if (getBundleServletContext().isHostBundle())
        webXmlFileName = WebBundleUtil.HOST_WEB_XML_NAME;
      IPath webXmlFilePath = new Path(webContentRoot.getAbsolutePath())
          .append("WEB-INF/" + webXmlFileName);
      File webXmlFile = webXmlFilePath.toFile();
      if (webXmlFile != null && webXmlFile.exists())
        return new FileInputStream(webXmlFile);
    }
    return null;
  }

  protected void initWebConfig() throws ServiceInitException {
    try {
      // Let sub class to provide singleton web.xml file, not only in a
      // WebContent folder.
      InputStream in = getWebXmlInput();
      if (in == null)
        return;

      SAXReader reader = new SAXReader();
      Document doc = reader.read(in);

      initServletContextParameters(doc);
      initServletContextListeners(doc);
      initJspConfigs(doc);
      // Init servlet filter and init each and init them.
      initServletContextFilters(doc);
      // Init servelts config and later we need init each servlet by its
      // load-on-setup paramater.

      initServlets(doc);
      initOthers(doc);
      webContainer.refresh();
    } catch (Exception e) {
      e.printStackTrace();
      throw new ServiceInitException(new Status(Status.ERROR, bundle
          .getSymbolicName(), "Initialize Web.xml configre failed["
          + this.getWebContextPath() + "].", e));
    }
  }

  /**
   * @param doc
   */
  private void initOthers(Document doc) {
    // Welcome pages
    Element welcomePageEle = doc.getRootElement().element(
        "welcome-file-list");
    if (welcomePageEle != null) {
      for (Iterator i = welcomePageEle.elementIterator("welcome-file"); i
          .hasNext();) {
        Element pEle = (Element) i.next();
        String page = pEle.getTextTrim();
        if (page != null && page != null) {
          servletContext.getWelcomePages().add(page);
        }
      }
    }

    // err pages
    for (Iterator i = doc.getRootElement().elementIterator("error-page"); i
        .hasNext();) {
      Element pEle = (Element) i.next();
      String code = pEle.elementTextTrim("error-code");
      String location = pEle.elementTextTrim("location");
      if (code != null && location != null && location.length() > 0) {
        try {
          servletContext.getErrorPages().put(Integer.parseInt(code),
              location);
        } catch (Exception e) {
          // e.printStackTrace();
        }
      }
    }

    // session valid interval in seconds.
    Element sessionConfigEle = doc.getRootElement().element(
        "session-config");
    if (sessionConfigEle != null) {
      String intervalStr = sessionConfigEle
          .elementText("session-timeout");
      if (intervalStr != null) {
        try {
          int interval = Integer.parseInt(intervalStr);
          // If interval set too big, the expiretion may be bigger the
          // Long.MAX_VALUE.
          if (interval > 0 && interval * 60 * 1000 < 0) {
            log(FwkActivator.LOG_ERROR, 0,
                "Session timeout to big. Use default timeout.",
                new IllegalAccessException(
                    "session-timeout too big"));
          } else {
            // session-timeout unit is minutes, and context need it
            // to be seconds.
            servletContext.setSessionTimeout(interval * 60);
          }
        } catch (NumberFormatException e) {
          log(FwkActivator.LOG_ERROR, 0, "Session timeout invalid.",
              e);
        }
      }
    }
  }

  /**
   * Register Jsp tag lib configure.
   *
   * @param httpService
   * @param doc
   * @param wb
   */
  private void initJspConfigs(Document doc) {
    /*
     * <jsp-config> <taglib> <taglib-uri>www.example.com/jsptag</taglib-uri>
     * <taglib-location>sagag.tlb</taglib-location> </taglib> </jsp-config>
     */
    for (Iterator i = doc.getRootElement().elementIterator("jsp-config"); i
        .hasNext();) {
      Element pEle = (Element) i.next();
      for (Iterator i1 = pEle.elementIterator("taglib"); i1.hasNext();) {
        Element pEle1 = (Element) i1.next();
        String uri = pEle.elementText("taglib-uri");
        String location = pEle.elementText("taglib-location");
        if (uri != null && location != null) {
          TaglibInfo info = new TaglibInfo();
          info.uri = uri;
          // Add web bundle prefix.
          info.location = this.getWebContextPath()
              + (location.startsWith("/") ? "" : "/") + location;
          servletContext.getTaglibs().add(info);
        }
      }
    }
  }

  private void initServletContextParameters(Document doc) {
    /*
     * <context-param> <param-name>contextConfigLocation</param-name>
     * <param-value>classpath:applicationContext.xml</param-value>
     * </context-param>
     */
    for (Iterator i = doc.getRootElement().elementIterator("context-param"); i
        .hasNext();) {
      Element pEle = (Element) i.next();
      String name = pEle.elementTextTrim("param-name");
      String value = pEle.elementTextTrim("param-value");
      if (!StringUtils.isEmpty(name) && !StringUtils.isEmpty(value)) {
        servletContext.setInitParameter(name, value);
      }
    }
  }

  private void initServletContextListeners(Document doc)
      throws ClassNotFoundException, InstantiationException,
      IllegalAccessException {
    /*
     * <listener>
     * <listener-class>org.springframework.web.context.ContextLoaderListener
     * </listener-class> </listener>
     */
    for (Iterator i = doc.getRootElement().elementIterator("listener"); i
        .hasNext();) {
      Element pEle = (Element) i.next();
      String clazzName = pEle.elementTextTrim("listener-class");
      if (clazzName != null && clazzName.length() > 0) {
        ListenerInfo info = new ListenerInfo();
        info.className = clazzName;
        info.setBundleContext(servletContext);
        servletContext.getListeners().add(info);
      }
    }
  }

  /**
   * @param httpService
   * @param wb
   * @param webBundles
   * @throws ClassNotFoundException
   * @throws IllegalAccessException
   * @throws InstantiationException
   * @throws ServletException
   */
  private void initServletContextFilters(Document doc)
      throws ClassNotFoundException, InstantiationException,
      IllegalAccessException, ServletException {
    /*
     * <filter> <filter-name>MoreContext</filter-name>
     * <filter-class>org.more.submit.support.web.SubmitRoot</filter-class>
     * <init-param> <param-name>buildClass</param-name>
     * <param-value>org.more
     * .submit.casing.spring.WebSpringBuilder</param-value> </init-param>
     * </filter> <filter-mapping>
     * <filter-name>bridge.servlet.filter</filter-name>
     * <servlet-name>equinoxbridgeservlet</servlet-name>
     * <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher>
     * <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher>
     * <dispatcher>INCLUDE</dispatcher> <dispatcher>EXCEPTION</dispatcher>
     * or <dispatcher>ERROR</dispatcher> </filter-mapping>
     */

    // Collect all filters at first.
    Map<String, FilterDelegateBase> filters = new HashMap<String, FilterDelegateBase>();
    // The order of filter decided by the order the map defined.
    for (Iterator i = doc.getRootElement().elementIterator("filter"); i
        .hasNext();) {
      Element pEle = (Element) i.next();
      String filterName = pEle.elementTextTrim("filter-name");
      if (StringUtils.isEmpty(filterName))
        continue;

      String clazzName = pEle.elementTextTrim("filter-class");
      if (StringUtils.isEmpty(clazzName))
        continue;

      Hashtable<String, String> params = new Hashtable<String, String>();
      for (Iterator i0 = pEle.elementIterator("init-param"); i0.hasNext();) {
        Element pEle0 = (Element) i0.next();
        String paramName = pEle0.elementTextTrim("param-name");
        String paramValue = pEle0.elementTextTrim("param-value");
        if (paramName != null && paramName.length() > 0
            && paramValue != null)
          params.put(paramName, paramValue);
      }

      FilterDelegateBase filter = new FilterDelegateBase();
      filter.clazzName = clazzName;
      filter.parameters = params;
      filter.name = filterName;
      filters.put(filterName, filter);
    }

    // Create filter delegate for each filter-mapping by define order.

    for (Iterator i1 = doc.getRootElement().elementIterator(
        "filter-mapping"); i1.hasNext();) {
      Element pEle1 = (Element) i1.next();
      String mapFilterName = pEle1.elementTextTrim("filter-name");
      if (StringUtils.isEmpty(mapFilterName))
        continue;

      FilterDelegateBase filter = filters.get(mapFilterName);
      if (filter == null)
        continue;

      String targetServletNames = null;
      String urlParttern = null;
      String dispatchers = null;
      // Search for mutiple dispatchers map at first.
      for (Iterator dispatchersIt = pEle1.elementIterator("dispatcher"); dispatchersIt
          .hasNext();) {

        String s = ((Element) dispatchersIt.next()).getTextTrim();
        // dispatcher type can only be one of REQUEST FORWARD
        // INCLUDE EXCEPTION/ERROR
        if (!StringUtils.isEmpty(s)
            && FilterDelegate.DISPATCHERS.valueOf(s) != null) {
          if (dispatchers == null)
            dispatchers = s;
          else
            dispatchers = dispatchers
                + FilterDelegate.DISPATCHERS_SEPERATOR + s;
        }
      }

      // Search for multiple URL-Pattern setting unders a
      // filter-mapping element.
      for (Iterator urlPatternIt = pEle1.elementIterator("url-pattern"); urlPatternIt
          .hasNext();) {
        String s = ((Element) urlPatternIt.next()).getTextTrim();
        if (StringUtils.isEmpty(s))
          continue;

        // if a IFwkConstants.SYS_PATH_PREFIX prefixed, not insert
        // bundle's service prefix.
        if (s.startsWith(IFwkConstants.SYS_PATH_PREFIX)) {
          s = s.substring(IFwkConstants.SYS_PATH_PREFIX.length());
        } else if (s != null && !servletContext.isHostBundle()) {
          // insert the name-space prefix of this web component to
          // each URL map pattern.
          s = this.getWebContextPath()
              + (s.startsWith("/") ? "" : "/") + s;
        }

        // Add the dispatcher marks before the URL map pattern if
        // any.
        if (!StringUtils.isEmpty(dispatchers))
          s = dispatchers
              + FilterDelegate.DISPATCHERS_PARTTERN_SEPERATOR + s;

        if (urlParttern == null)
          urlParttern = s;
        else
          urlParttern = urlParttern
              + FilterDelegate.MULTI_MAP_SEG_SEPERATOR + s;
      }

      // Search for multiple servlet map.
      for (Iterator servletMapIt = pEle1.elementIterator("servlet-name"); servletMapIt
          .hasNext();) {
        String s = ((Element) servletMapIt.next()).getTextTrim();
        if (StringUtils.isEmpty(s))
          continue;

        // Add the dispatcher marks before the url map parttern if
        // any.
        if (!StringUtils.isEmpty(dispatchers))
          s = dispatchers
              + FilterDelegate.DISPATCHERS_PARTTERN_SEPERATOR + s;

        if (s != null && s.length() != 0) {
          if (targetServletNames == null)
            targetServletNames = s;
          else
            targetServletNames = targetServletNames
                + FilterDelegate.MULTI_MAP_SEG_SEPERATOR + s;
        }
      }
      FilterDelegate info = new FilterDelegate(filter);
      info.targetServletNames = targetServletNames;
      info.setRawURLPatterns(urlParttern);
      info.setBundleContext(servletContext);
      servletContext.getFilters().add(info);
      // Do not init filter, we init them later before servelts.
      // info.init(null);
    }
  }

  /**
   * @param httpService
   * @param wb
   * @throws ClassNotFoundException
   * @throws NamespaceException
   * @throws ServletException
   * @throws IllegalAccessException
   * @throws InstantiationException
   */
  private void initServlets(Document doc) throws ClassNotFoundException,
      ServletException, NamespaceException, InstantiationException,
      IllegalAccessException {
    // servlet: servlet-name servlet-class init-param
    // servlet-mapping: servlet-name url-pattern
    for (Iterator i = doc.getRootElement().elementIterator("servlet"); i
        .hasNext();) {
      Element pEle = (Element) i.next();
      String servletName = pEle.elementTextTrim("servlet-name");
      if (servletName == null || servletName.length() == 0)
        continue;

      // Do not forget the jsp file element.<jsp-file>/abc.jsp</jsp-file>
      String clazzName = pEle.elementTextTrim("servlet-class");
      String jspFilePath = null;
      if (clazzName == null || clazzName.length() == 0) {
        jspFilePath = pEle.elementTextTrim("jsp-file");
        if (jspFilePath == null && jspFilePath.length() > 0)
          continue;
      }

      int loadOnSetupPriority = 0;

      try {
        loadOnSetupPriority = Integer.parseInt(pEle
            .elementTextTrim("load-on-startup"));
      } catch (Exception e) {
        // e.printStackTrace();
      }

      Hashtable<String, String> params = new Hashtable<String, String>();

      for (Iterator i0 = pEle.elementIterator("init-param"); i0.hasNext();) {
        Element pEle0 = (Element) i0.next();
        String paramName = pEle0.elementTextTrim("param-name");
        String paramValue = pEle0.elementTextTrim("param-value");
        if (!StringUtils.isEmpty(paramName) && paramValue != null)
          params.put(paramName, paramValue);
      }

      String urlParttern = null;
      for (Iterator i1 = doc.getRootElement().elementIterator(
          "servlet-mapping"); i1.hasNext();) {
        Element pEle1 = (Element) i1.next();
        String mapName = pEle1.elementTextTrim("servlet-name");
        if (mapName == null || mapName.length() == 0
            || !mapName.equals(servletName))
          continue;

        // Parse multiple URL-Pattern setting unders a servlet-mapping
        // element.
        for (Iterator urlPatternIt = pEle1
            .elementIterator("url-pattern"); urlPatternIt.hasNext();) {
          Element urlPatternEle = (Element) urlPatternIt.next();
          String s = urlPatternEle.getTextTrim();
          if (s == null || s.length() == 0)
            continue;

          // if a IFwkConstants.SYS_PATH_PREFIX prefixed, not insert
          // bundle's service prefix.
          if (s.startsWith(IFwkConstants.SYS_PATH_PREFIX)) {
            s = s.substring(IFwkConstants.SYS_PATH_PREFIX.length());
          } else if (!servletContext.isHostBundle()) {
            // insert the namespace prefix of this web component to
            // each url map parttern.
            s = this.getWebContextPath()
                + (s.startsWith("/") ? "" : "/") + s;
          }

          if (urlParttern == null)
            urlParttern = s;
          else
            urlParttern = urlParttern
                + FilterDelegate.MULTI_MAP_SEG_SEPERATOR + s;
        }
      }

      ServletDelegate info = new ServletDelegate();
      info.name = servletName;
      info.className = clazzName;
      info.jspFile = jspFilePath;
      info.setRawURLPatterns(urlParttern);
      info.parameters = params;
      info.loadOnSetupPriority = loadOnSetupPriority;
      info.setBundleContext(servletContext);
      servletContext.getServletsInfo().add(info);
    }
  }

  public void log(IOException e) {
    FwkActivator.getInstance().log(e);
  }

  public void log(int severity, int code, String message, Throwable t) {
    FwkActivator.getInstance().log(severity, code, message, t);
  }

  public void log(Status status) {
    FwkActivator.getInstance().log(status);
  }
}
TOP

Related Classes of org.emrys.webosgi.core.runtime.WebApplication

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.