/**
  * Initialization.
  *
  * @throws ServletException
  */
 @SuppressWarnings("cast")
 @Override
 public void start() throws ServletException {
   log.info("Loading tomcat virtual host");
   if (webappFolder != null) {
     // check for match with base webapp root
     if (webappFolder.equals(webappRoot)) {
       log.error("Web application root cannot be the same as base");
       return;
     }
   }
   ClassLoader classloader = Thread.currentThread().getContextClassLoader();
   // ensure we have a host
   if (host == null) {
     host = createHost();
   }
   host.setParentClassLoader(classloader);
   String propertyPrefix = name;
   if (domain != null) {
     propertyPrefix += '_' + domain.replace('.', '_');
   }
   log.debug("Generating name (for props) {}", propertyPrefix);
   System.setProperty(propertyPrefix + ".webapp.root", webappRoot);
   log.info("Virtual host root: {}", webappRoot);
   log.info("Virtual host context id: {}", defaultApplicationContextId);
   // Root applications directory
   File appDirBase = new File(webappRoot);
   // Subdirs of root apps dir
   File[] dirs = appDirBase.listFiles(new TomcatLoader.DirectoryFilter());
   // Search for additional context files
   for (File dir : dirs) {
     String dirName = '/' + dir.getName();
     // check to see if the directory is already mapped
     if (null == host.findChild(dirName)) {
       String webappContextDir = FileUtil.formatPath(appDirBase.getAbsolutePath(), dirName);
       Context ctx = null;
       if ("/root".equals(dirName) || "/root".equalsIgnoreCase(dirName)) {
         log.debug("Adding ROOT context");
         ctx = addContext("/", webappContextDir);
       } else {
         log.debug("Adding context from directory scan: {}", dirName);
         ctx = addContext(dirName, webappContextDir);
       }
       log.debug("Context: {}", ctx);
       webappContextDir = null;
     }
   }
   appDirBase = null;
   dirs = null;
   // Dump context list
   if (log.isDebugEnabled()) {
     for (Container cont : host.findChildren()) {
       log.debug("Context child name: {}", cont.getName());
     }
   }
   engine.addChild(host);
   // Start server
   try {
     log.info("Starting Tomcat virtual host");
     // may not have to do this step for every host
     LoaderBase.setApplicationLoader(
         new TomcatApplicationLoader(embedded, host, applicationContext));
     for (Container cont : host.findChildren()) {
       if (cont instanceof StandardContext) {
         StandardContext ctx = (StandardContext) cont;
         ServletContext servletContext = ctx.getServletContext();
         log.debug("Context initialized: {}", servletContext.getContextPath());
         // set the hosts id
         servletContext.setAttribute("red5.host.id", getHostId());
         String prefix = servletContext.getRealPath("/");
         log.debug("Path: {}", prefix);
         try {
           Loader cldr = ctx.getLoader();
           log.debug("Loader type: {}", cldr.getClass().getName());
           ClassLoader webClassLoader = cldr.getClassLoader();
           log.debug("Webapp classloader: {}", webClassLoader);
           // create a spring web application context
           XmlWebApplicationContext appctx = new XmlWebApplicationContext();
           appctx.setClassLoader(webClassLoader);
           appctx.setConfigLocations(new String[] {"/WEB-INF/red5-*.xml"});
           // check for red5 context bean
           if (applicationContext.containsBean(defaultApplicationContextId)) {
             appctx.setParent(
                 (ApplicationContext) applicationContext.getBean(defaultApplicationContextId));
           } else {
             log.warn(
                 "{} bean was not found in context: {}",
                 defaultApplicationContextId,
                 applicationContext.getDisplayName());
             // lookup context loader and attempt to get what we need from it
             if (applicationContext.containsBean("context.loader")) {
               ContextLoader contextLoader =
                   (ContextLoader) applicationContext.getBean("context.loader");
               appctx.setParent(contextLoader.getContext(defaultApplicationContextId));
             } else {
               log.debug("Context loader was not found, trying JMX");
               MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
               // get the ContextLoader from jmx
               ContextLoaderMXBean proxy = null;
               ObjectName oName = null;
               try {
                 oName = new ObjectName("org.red5.server:name=contextLoader,type=ContextLoader");
                 if (mbs.isRegistered(oName)) {
                   proxy = JMX.newMXBeanProxy(mbs, oName, ContextLoaderMXBean.class, true);
                   log.debug("Context loader was found");
                   proxy.setParentContext(defaultApplicationContextId, appctx.getId());
                 } else {
                   log.warn("Context loader was not found");
                 }
               } catch (Exception e) {
                 log.warn("Exception looking up ContextLoader", e);
               }
             }
           }
           if (log.isDebugEnabled()) {
             if (appctx.getParent() != null) {
               log.debug("Parent application context: {}", appctx.getParent().getDisplayName());
             }
           }
           //
           appctx.setServletContext(servletContext);
           // set the root webapp ctx attr on the each servlet context so spring can find it later
           servletContext.setAttribute(
               WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, appctx);
           appctx.refresh();
         } catch (Throwable t) {
           log.error("Error setting up context: {}", servletContext.getContextPath(), t);
           if (log.isDebugEnabled()) {
             t.printStackTrace();
           }
         }
       }
     }
   } catch (Exception e) {
     log.error("Error loading Tomcat virtual host", e);
   }
 }
  /**
   * Starts a web application and its red5 (spring) component. This is basically a stripped down
   * version of init().
   *
   * @return true on success
   * @throws ServletException
   */
  @SuppressWarnings("cast")
  public boolean startWebApplication(String applicationName) throws ServletException {
    boolean result = false;
    log.info("Starting Tomcat virtual host - Web application");
    log.info("Virtual host root: {}", webappRoot);
    log.info("Virtual host context id: {}", defaultApplicationContextId);
    // application directory
    String contextName = '/' + applicationName;
    Container cont = null;
    // check if the context already exists for the host
    if ((cont = host.findChild(contextName)) == null) {
      log.debug("Context did not exist in host");
      String webappContextDir = FileUtil.formatPath(webappRoot, applicationName);
      // prepend slash
      Context ctx = addContext(contextName, webappContextDir);
      // set the newly created context as the current container
      cont = ctx;
    } else {
      log.debug("Context already exists in host");
    }
    try {
      ServletContext servletContext = ((Context) cont).getServletContext();
      log.debug("Context initialized: {}", servletContext.getContextPath());
      String prefix = servletContext.getRealPath("/");
      log.debug("Path: {}", prefix);
      Loader cldr = ((Context) cont).getLoader();
      log.debug("Loader type: {}", cldr.getClass().getName());
      ClassLoader webClassLoader = cldr.getClassLoader();
      log.debug("Webapp classloader: {}", webClassLoader);
      // create a spring web application context
      XmlWebApplicationContext appctx = new XmlWebApplicationContext();
      appctx.setClassLoader(webClassLoader);
      appctx.setConfigLocations(new String[] {"/WEB-INF/red5-*.xml"});
      // check for red5 context bean
      if (applicationContext.containsBean(defaultApplicationContextId)) {
        appctx.setParent(
            (ApplicationContext) applicationContext.getBean(defaultApplicationContextId));
      } else {
        log.warn(
            "{} bean was not found in context: {}",
            defaultApplicationContextId,
            applicationContext.getDisplayName());
        // lookup context loader and attempt to get what we need from it
        if (applicationContext.containsBean("context.loader")) {
          ContextLoader contextLoader =
              (ContextLoader) applicationContext.getBean("context.loader");
          appctx.setParent(contextLoader.getContext(defaultApplicationContextId));
        } else {
          log.debug("Context loader was not found, trying JMX");
          MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
          // get the ContextLoader from jmx
          ContextLoaderMXBean proxy = null;
          ObjectName oName = null;
          try {
            oName = new ObjectName("org.red5.server:name=contextLoader,type=ContextLoader");
            if (mbs.isRegistered(oName)) {
              proxy = JMX.newMXBeanProxy(mbs, oName, ContextLoaderMXBean.class, true);
              log.debug("Context loader was found");
              proxy.setParentContext(defaultApplicationContextId, appctx.getId());
            } else {
              log.warn("Context loader was not found");
            }
          } catch (Exception e) {
            log.warn("Exception looking up ContextLoader", e);
          }
        }
      }
      if (log.isDebugEnabled()) {
        if (appctx.getParent() != null) {
          log.debug("Parent application context: {}", appctx.getParent().getDisplayName());
        }
      }
      //
      appctx.setServletContext(servletContext);
      // set the root webapp ctx attr on the each servlet context so spring can find it later
      servletContext.setAttribute(
          WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, appctx);
      appctx.refresh();
      result = true;
    } catch (Throwable t) {
      log.error("Error setting up context: {}", applicationName, t);
      if (log.isDebugEnabled()) {
        t.printStackTrace();
      }
    }

    return result;
  }