/**
   * Method that will create and add an ActionForward to a ActionMapping, this call is mandatory for
   * the creation of ActionForwards because extra logic will be required for jsp forwards to work.
   *
   * @param actionMapping
   * @param name
   * @param path
   * @param redirect
   * @return
   * @throws Exception
   */
  protected ForwardConfig registerActionForward(
      BundleContext context,
      ActionMapping actionMapping,
      String name,
      String path,
      Boolean redirect)
      throws Exception {

    if (!path.startsWith(PATH_SEPARATOR)) {
      path = PATH_SEPARATOR + path;
    }

    String forwardMapping = activatorUtil.getBundleFolder(context) + path;

    // Creating an ForwardConfig Instance
    ForwardConfig forwardConfig = new ActionForward(name, forwardMapping, redirect);
    // Adding the ForwardConfig to the ActionConfig
    actionMapping.addForwardConfig(forwardConfig);

    // Copy all the resources inside the folder of the given resource to the corresponding dotCMS
    // folders
    activatorUtil.moveResources(context, path);

    return forwardConfig;
  }
  /**
   * Allow to this bundle/elements to be visible and accessible from the host classpath
   *
   * @param context
   * @throws Exception
   */
  protected void publishBundleServices(BundleContext context) throws Exception {

    // Classloaders
    ClassLoader felixClassLoader = getFelixClassLoader();
    ClassLoader contextClassLoader = getContextClassLoader();

    // Create a new class loader where we can "combine" our classloaders
    CombinedLoader combinedLoader;
    if (contextClassLoader instanceof CombinedLoader) {
      combinedLoader = (CombinedLoader) contextClassLoader;
      combinedLoader.addLoader(felixClassLoader);
    } else {
      combinedLoader = new CombinedLoader(contextClassLoader);
      combinedLoader.addLoader(felixClassLoader);
    }

    // Force the loading of some classes that may be already loaded on the host classpath but we
    // want to override with the ones on this bundle and we specified
    String overrideClasses =
        activatorUtil.getManifestHeaderValue(context, MANIFEST_HEADER_OVERRIDE_CLASSES);
    if (overrideClasses != null && !overrideClasses.isEmpty()) {

      String[] forceOverride = overrideClasses.split(",");
      if (forceOverride.length > 0) {

        try {
          // Get the activator class for this OSGI bundle
          String activatorClass =
              activatorUtil.getManifestHeaderValue(context, MANIFEST_HEADER_BUNDLE_ACTIVATOR);
          // Injecting this bundle context code inside the dotCMS context
          injectContext(activatorClass);
        } catch (Exception e) {
          Logger.error(this, "Error injecting context for overriding", e);
          throw e;
        }

        for (String classToOverride : forceOverride) {
          try {
            /*
            Loading the custom implementation will allows to override the one the ClassLoader
            already had loaded and use it on this OSGI bundle context
            */
            combinedLoader.loadClass(classToOverride.trim());
          } catch (Exception e) {
            Logger.error(this, "Error overriding class: " + classToOverride, e);
            throw e;
          }
        }
      }
    }

    // Use this new "combined" class loader
    Thread.currentThread().setContextClassLoader(combinedLoader);
  }
  /**
   * Register the portlets on the given configuration files
   *
   * @param xmls
   * @throws Exception
   */
  @SuppressWarnings("unchecked")
  protected Collection<Portlet> registerPortlets(BundleContext context, String[] xmls)
      throws Exception {

    String[] confFiles =
        new String[] {
          Http.URLtoString(context.getBundle().getResource(xmls[0])),
          Http.URLtoString(context.getBundle().getResource(xmls[1]))
        };

    // Read the portlets xml files and create them
    portlets = PortletManagerUtil.initWAR(null, confFiles);

    for (Portlet portlet : portlets) {

      if (portlet.getPortletClass().equals("com.liferay.portlet.JSPPortlet")) {

        Map initParams = portlet.getInitParams();
        String jspPath = (String) initParams.get(INIT_PARAM_VIEW_JSP);

        if (!jspPath.startsWith(PATH_SEPARATOR)) {
          jspPath = PATH_SEPARATOR + jspPath;
        }

        // Copy all the resources inside the folder of the given resource to the corresponding
        // dotCMS folders
        activatorUtil.moveResources(context, jspPath);
        portlet
            .getInitParams()
            .put(INIT_PARAM_VIEW_JSP, activatorUtil.getBundleFolder(context) + jspPath);
      } else if (portlet.getPortletClass().equals("com.liferay.portlet.VelocityPortlet")) {

        Map initParams = portlet.getInitParams();
        String templatePath = (String) initParams.get(INIT_PARAM_VIEW_TEMPLATE);

        if (!templatePath.startsWith(PATH_SEPARATOR)) {
          templatePath = PATH_SEPARATOR + templatePath;
        }

        // Copy all the resources inside the folder of the given resource to the corresponding
        // velocity dotCMS folders
        activatorUtil.moveVelocityResources(context, templatePath);
        portlet
            .getInitParams()
            .put(INIT_PARAM_VIEW_TEMPLATE, activatorUtil.getBundleFolder(context) + templatePath);
      }

      Logger.info(this, "Added Portlet: " + portlet.getPortletId());
    }

    return portlets;
  }
  /**
   * Unregister all the registered ActionMappings
   *
   * @throws Exception
   */
  protected void unregisterActionMappings() throws Exception {

    if (actions != null) {

      ModuleConfig moduleConfig = activatorUtil.getModuleConfig();
      // We need to unfreeze this module in order to add new action mappings
      activatorUtil.unfreeze(moduleConfig);

      for (ActionConfig actionConfig : actions) {
        moduleConfig.removeActionConfig(actionConfig);
      }
      moduleConfig.freeze();
    }
  }
  /**
   * Register a given ActionMapping
   *
   * @param actionMapping
   * @throws Exception
   */
  protected void registerActionMapping(ActionMapping actionMapping) throws Exception {

    if (actions == null) {
      actions = new ArrayList<ActionConfig>();
    }

    String actionClassType = actionMapping.getType();

    // Will inject the action classes inside the dotCMS context
    injectContext(actionClassType);

    ModuleConfig moduleConfig = activatorUtil.getModuleConfig();
    // We need to unfreeze this module in order to add new action mappings
    activatorUtil.unfreeze(moduleConfig);

    // Adding the ActionConfig to the ForwardConfig
    moduleConfig.addActionConfig(actionMapping);
    // moduleConfig.freeze();

    actions.add(actionMapping);
    Logger.info(this, "Added Struts Action Mapping: " + actionClassType);
  }
  /**
   * Utility method to unregister all the possible services and/or tools registered by this
   * activator class. Some how we have to try to clean up anything added on the deploy if this
   * bundle.
   */
  protected void unregisterServices(BundleContext context) throws Exception {

    unregisterActionlets();
    unregisterViewToolServices();
    unpublishBundleServices();
    unregisterPreHooks();
    unregisterPostHooks();
    unregisterQuartzJobs();
    unregisterActionMappings();
    unregisterPortles();
    unregisterServlets(context);
    unregisterRewriteRule();
    activatorUtil.cleanResources(context);
  }
  /**
   * Will inject this bundle context code inside the dotCMS context
   *
   * @param className a reference class inside this bundle jar
   * @param reload if a redefinition should be done or not
   * @throws Exception
   */
  private void injectContext(String className, Boolean reload) throws Exception {

    // Get the location of this OSGI bundle jar source code using a known class inside this bundle
    Class clazz = Class.forName(className, false, getFelixClassLoader());
    URL classURL = clazz.getProtectionDomain().getCodeSource().getLocation();

    // Verify if we have our UrlOsgiClassLoader on the main class loaders
    UrlOsgiClassLoader urlOsgiClassLoader =
        activatorUtil.findCustomURLLoader(ClassLoader.getSystemClassLoader());
    if (urlOsgiClassLoader != null) {

      if (!urlOsgiClassLoader.contains(
          classURL)) { // Verify if this URL is already in our custom ClassLoader
        urlOsgiClassLoader.addURL(classURL);
      }

      // The ClassLoader and the class content is already in the system ClassLoader, so we need to
      // reload the jar contents
      if (reload) {
        urlOsgiClassLoader.reload(classURL);
      }
    } else {

      // Getting the reference of a known class in order to get the base/main class loader
      Class baseClass = getContextClassLoader().loadClass("org.quartz.Job");
      // Creates our custom class loader in order to use it to inject the class code inside dotcms
      // context
      urlOsgiClassLoader = new UrlOsgiClassLoader(classURL, baseClass.getClassLoader());

      // We may have classes we want to override from e beginning, for example a custom
      // implementation of a dotCMS class
      if (reload) {
        urlOsgiClassLoader.reload(classURL);
      }

      // Linking our custom class loader with the dotCMS class loaders hierarchy.
      urlOsgiClassLoader.linkClassLoaders();
    }
  }
 /**
  * Unregister all the registered servlets and mappings
  *
  * @throws SchedulerException
  */
 protected void unregisterServlets(BundleContext context) throws Exception {
   activatorUtil.unregisterAll(context);
 }