/** Created by The eXo Platform SAS Author : Nguyen Thanh Hai [email protected] Jun 29, 2011 */
public class MimeTypeUploadPlugin extends BaseComponentPlugin {
  private static final Logger log = LoggerFactory.getLogger(MimeTypeUploadPlugin.class);
  private static final String MIMETYPE_PATH = "mimetype-path";
  private static final String DEFAULT_MIMETYPE = "mimetype-default";

  private Properties mimeTypes = new Properties();
  private String mimetypeDefault;

  public MimeTypeUploadPlugin(InitParams initParams, ConfigurationManager configurationService)
      throws Exception {
    ValueParam param = initParams.getValueParam(MIMETYPE_PATH);
    URL filePath = configurationService.getURL(param.getValue());
    URLConnection connection = filePath.openConnection();
    mimeTypes.load(connection.getInputStream());

    param = initParams.getValueParam(DEFAULT_MIMETYPE);
    if (param != null) mimetypeDefault = param.getValue();
  }

  public String getMimeType(String fileName) {
    if (fileName.indexOf('.') == -1) return mimetypeDefault;
    String ext = fileName.substring(fileName.lastIndexOf('.') + 1);
    String mimeType = mimeTypes.getProperty(ext.toLowerCase(), mimetypeDefault);
    if (mimeType == null || mimeType.length() == 0) return null;
    return mimeType;
  }
}
/**
 * Kernel component, which holds references to all configured {@link
 * org.gatein.sso.agent.filter.api.SSOInterceptor} instances
 *
 * @author <a href="mailto:[email protected]">Marek Posolda</a>
 */
public class SSOFilterIntegratorImpl implements SSOFilterIntegrator {
  // Key is filter (SSOInterceptor), value is filterMapping
  private final Map<SSOInterceptor, String> ssoInterceptors =
      new LinkedHashMap<SSOInterceptor, String>();

  private static final Logger log = LoggerFactory.getLogger(SSOFilterIntegratorImpl.class);

  public void addPlugin(ComponentPlugin plugin) {
    if (plugin instanceof SSOFilterIntegratorPlugin) {
      SSOFilterIntegratorPlugin ssoPlugin = (SSOFilterIntegratorPlugin) plugin;

      if (!ssoPlugin.isEnabled()) {
        return;
      }

      SSOInterceptor ssoInterceptor = ssoPlugin.getFilter();
      this.ssoInterceptors.put(ssoInterceptor, ssoPlugin.getFilterMapping());

      log.debug("Added new SSOInterceptor " + ssoInterceptor);
    }
  }

  public Map<SSOInterceptor, String> getSSOInterceptors() {
    return ssoInterceptors;
  }
}
/**
 * @author <a href="mailto:[email protected]">Julien Viet</a>
 * @version $Revision$
 */
public abstract class AbstractGateInTest extends TestCase {

  /** . */
  protected final Logger log = LoggerFactory.getLogger(getClass());

  protected AbstractGateInTest() {}

  protected AbstractGateInTest(String name) {
    super(name);
  }

  protected void beforeRunBare() throws Exception {
    //
  }

  /** After the run base, it should not throw anything as it is executed in a finally clause. */
  protected void afterRunBare() {
    //
  }

  @Override
  public final void runBare() throws Throwable {
    // Patch a bug with maven that does not pass properly the system property
    // with an empty value
    if ("org.hsqldb.jdbcDriver".equals(System.getProperty("gatein.test.datasource.driver"))) {
      System.setProperty("gatein.test.datasource.password", "");
    }

    //
    log.info("Running unit test:" + getName());
    for (Map.Entry<?, ?> entry : System.getProperties().entrySet()) {
      if (entry.getKey() instanceof String) {
        String key = (String) entry.getKey();
        log.debug(key + "=" + entry.getValue());
      }
    }

    //
    beforeRunBare();

    //
    try {
      super.runBare();
      log.info("Unit test " + getName() + " completed");
    } catch (Throwable throwable) {
      log.error("Unit test " + getName() + " did not complete", throwable);

      //
      throw throwable;
    } finally {
      afterRunBare();
    }
  }
}
Beispiel #4
0
/** @author <a href="mailto:[email protected]">Sohil Shah</a> */
public class CASAgentImpl extends GenericAgent implements CASAgent {
  private static Logger log = LoggerFactory.getLogger(CASAgentImpl.class);

  private String casServerUrl;
  private boolean renewTicket;
  private String casServiceUrl;

  public CASAgentImpl(InitParams params) {
    // TODO: Read casServerUrl and casServiceUrl from params
  }

  public void setCasServerUrl(String casServerUrl) {
    this.casServerUrl = casServerUrl;
  }

  public void setCasServiceUrl(String casServiceUrl) {
    this.casServiceUrl = casServiceUrl;
  }

  public void setRenewTicket(boolean renewTicket) {
    this.renewTicket = renewTicket;
  }

  public void validateTicket(HttpServletRequest httpRequest, String ticket) throws Exception {
    Cas20ProxyTicketValidator ticketValidator = new Cas20ProxyTicketValidator(casServerUrl);
    ticketValidator.setRenew(this.renewTicket);

    // String serviceUrl = "http://"+ httpRequest.getServerName() +":" + httpRequest.getServerPort()
    // +
    // httpRequest.getContextPath() +"/private/classic";
    Assertion assertion = ticketValidator.validate(ticket, this.casServiceUrl);

    log.debug(
        "------------------------------------------------------------------------------------");
    log.debug("Service: " + this.casServiceUrl);
    log.debug("Principal: " + assertion.getPrincipal().getName());
    log.debug(
        "------------------------------------------------------------------------------------");

    String principal = assertion.getPrincipal().getName();
    this.saveSSOCredentials(principal, httpRequest);
  }
}
Beispiel #5
0
/**
 * @author <a href="mailto:[email protected]">Nick Scavelli</a>
 * @version $Revision$
 */
public class Importer {
  private static final Logger log = LoggerFactory.getLogger(Importer.class);

  @Option(
      name = "--config",
      aliases = "-c",
      usage = "Sets custom configuration file to be used for import.",
      metaVar = " ")
  File configFile;

  @Option(
      name = "--log4j",
      aliases = "-l",
      usage = "Sets custom log4j config file to be used for logging.",
      metaVar = " ")
  File log4jFile;

  @Option(
      name = "--loglevel",
      usage = "Sets log level of root log4j logger (ie debug, info).",
      metaVar = " ")
  String logLevel;

  @Option(
      name = "--username",
      aliases = "-u",
      usage = "Username to connect to portal with.",
      metaVar = " ")
  String username;

  @Option(
      name = "--password",
      aliases = "-p",
      usage = "Password to connect to portal with.",
      metaVar = " ")
  String password;

  @Option(
      name = "--host",
      aliases = "-h",
      usage = "Host of the server the portal is running on.",
      metaVar = " ")
  String host;

  @Option(name = "--port", usage = "Port of the server the portal is running on.", metaVar = " ")
  int port;

  @Option(
      name = "--portalcontainer",
      aliases = "-pc",
      usage = "Portal container name (ie portal).",
      metaVar = " ")
  String portalContainer;

  @Argument(usage = "Path to import file", metaVar = "import file")
  File importFile;

  @Option(
      name = "--overwrite",
      aliases = "-o",
      usage =
          "Indicates that the contents of each file should overwrite everything on the destination server. This also means that anything not included will be deleted.",
      metaVar = " ")
  Boolean overwrite;

  @Option(
      name = "--force",
      aliases = "-f",
      usage = "Force all options without confirmation.",
      metaVar = " ")
  boolean force;

  @Option(name = "--help")
  boolean help;

  private PortalObjectsMgmtClient client;
  int level;

  void init() {
    portalContainer = Utils.trimToNull(portalContainer);

    if (importFile == null) {
      String file = Utils.getUserInput("Import file", level);
      importFile = new File(file);
    }
    if (!importFile.exists()) {
      System.err.println("Cannot find file " + importFile);
      System.exit(1);
    }

    File importDir = importFile.getParentFile();
    if (importDir == null) importDir = new File(".");

    Utils.initializeLogging(log4jFile, logLevel, importDir, importFile.getName(), "import");
  }

  public void doImport() {
    if (portalContainer == null) {
      portalContainer = Utils.getUserInput("Container name (ie portal)", level);
    }

    try {
      client =
          PortalObjectsMgmtClient.Factory.create(
              InetAddress.getByName(host), port, username, password, portalContainer);
    } catch (UnknownHostException e) {
      System.err.println("Unknown host name " + host + ". See log for more details.");
      log.error("Exception retrieving host " + host + " by name.", e);
      System.exit(1);
    }

    if (overwrite == null) {
      String ow =
          Utils.getUserInput(
              "Do you wish to fully overwrite all data defined in import file (N) ? Y/N", level);
      if ("Y".equalsIgnoreCase(ow)) {
        overwrite = Boolean.TRUE;
      } else {
        overwrite = Boolean.FALSE;
      }
    }

    if (overwrite && !force) {
      System.out.println(
          "\nOverwrite set to true. This means that all data for a site will be overwritten and any data not defined will be deleted.");
      String proceed = Utils.getUserInput("Do you wish to proceed (N) ? Y/N", level);
      if (!"Y".equalsIgnoreCase(proceed)) {
        System.exit(0);
      }
    }

    log.info("Starting import of file " + importFile + " for portal container " + portalContainer);
    try {
      ImportContext context = client.importFromZip(importFile);
      if (isEmptyContext(context)) {
        System.out.println(
            "Nothing to import. " + importFile + " did not contain anything to import.");
        log.warn("Nothing imported. Zip file did not contain any data for import.");
        System.exit(0);
      }

      if (overwrite) {
        log.info("Overwrite set to true, overwriting all data.");
      }
      context.setOverwrite(overwrite);
      client.importContext(context);
      log.info("Import was successful.");
    } catch (IOException e) {
      System.err.println("Exception reading zip file. See log for more details.");
      log.error("IOException reading zip file " + importFile, e);
    } catch (ClientException e) {
      System.err.println("Client exception during import. See log for more details.");
      log.error("ClientException during import.", e);
    } catch (Throwable t) {
      System.err.println("Unknown exception occurred during import.  See log for more details.");
      log.error("Uknown exception during import.", t);
    }
  }

  private boolean isEmptyContext(ImportContext context) {
    return (context.getPortalConfigs().isEmpty()
        && context.getPages().isEmpty()
        && context.getNavigations().isEmpty());
  }
}
/**
 * @author <a href="*****@*****.**">Minh Hoang TO</a>
 * @date 1/8/13
 */
@Managed
@ManagedDescription("Navigation data injector")
@NameTemplate({
  @Property(key = "view", value = "portal"),
  @Property(key = "service", value = "navigationInjector"),
  @Property(key = "type", value = "navdataInject")
})
@RESTEndpoint(path = "navInjector")
public class NavigationDataInjector extends AbstractInjector {
  private static Logger LOG = LoggerFactory.getLogger(NavigationDataInjector.class);

  private NavigationServiceWrapper navService;

  private DataStorage dataStorage;

  public NavigationDataInjector(NavigationServiceWrapper _navService, DataStorage _dataStorage) {
    navService = _navService;
    dataStorage = _dataStorage;
  }

  @Override
  public Logger getLogger() {
    return LOG;
  }

  public void createNavigation(String type, String owner, List<String> children) {
    SiteKey key = new SiteKey(type, owner);
    NavigationContext navCtx = navService.loadNavigation(key);
    if (navCtx != null) {
      LOG.error("Navigation type= " + type + " , owner= " + owner + " already exists");
    } else {
      try {
        if (dataStorage.getPortalConfig(type, owner) == null) {
          dataStorage.create(new PortalConfig(type, owner));
        }
      } catch (Exception ex) {
        LOG.error("Error while load/create site ( type= " + type + " , owner = " + owner, ex);
      }

      navCtx = new NavigationContext(key, new NavigationState(0));
      NavNode rootNode =
          navService.loadNode(new NavNodeModel(), navCtx, Scope.CHILDREN, null).getNode();
      int index = 0;
      for (String child : children) {
        rootNode.addChild(index, child);
        index++;
      }
      navService.saveNode(rootNode.context, null);
    }
  }

  public void createNavigation(
      String type, String owner, String prefix, int startIndex, int endIndex) {
    if (startIndex < endIndex) {
      SiteKey key = new SiteKey(type, owner);
      NavigationContext navCtx = navService.loadNavigation(key);
      if (navCtx != null) {
        LOG.error("Navigation type= " + type + " , owner= " + owner + " already exists");
      } else {
        try {
          if (dataStorage.getPortalConfig(type, owner) == null) {
            dataStorage.create(new PortalConfig(type, owner));
          }
        } catch (Exception ex) {
          LOG.error("Error while load/create site ( type= " + type + " , owner = " + owner, ex);
        }

        navService.saveNavigation(new NavigationContext(key, new NavigationState(0)));
        navCtx = navService.loadNavigation(key);
        NavNode rootNode =
            navService.loadNode(new NavNodeModel(), navCtx, Scope.CHILDREN, null).getNode();
        for (int i = startIndex; i < endIndex; i++) {
          rootNode.addChild(i, prefix + "_" + i);
        }
        navService.saveNode(rootNode.context, null);
      }
    }
  }

  public void addNodes(String navType, String navOwner, List<String> nodeNames) {
    SiteKey key = new SiteKey(navType, navOwner);
    NavigationContext navCtx = navService.loadNavigation(key);
    if (navCtx == null) {
      LOG.error("Navigation type= " + navType + " , owner= " + navOwner + " does not exist");
    } else {
      NavNode rootNode =
          navService.loadNode(new NavNodeModel(), navCtx, Scope.CHILDREN, null).getNode();
      int index = rootNode.getSize();
      for (String nodeName : nodeNames) {
        if (rootNode.getChild(nodeName) != null) {
          LOG.debug(
              "Navigation node named " + nodeName + " already exist, will not add it anymore");
        } else {
          rootNode.addChild(index, nodeName);
          index++;
        }
      }
      navService.saveNode(rootNode.context, null);
    }
  }

  public void addNodes(
      String navType, String navOwner, String nodePrefix, int startIndex, int endIndex) {
    if (startIndex < endIndex) {
      SiteKey key = new SiteKey(navType, navOwner);
      NavigationContext navCtx = navService.loadNavigation(key);
      if (navCtx == null) {
        LOG.error("Navigation type= " + navType + " , owner= " + navOwner + " does not exist");
      } else {
        NavNode rootNode =
            navService.loadNode(new NavNodeModel(), navCtx, Scope.CHILDREN, null).getNode();
        int index = rootNode.getSize();
        for (int i = startIndex; i < endIndex; i++) {
          String nodeName = nodePrefix + "_" + i;
          if (rootNode.getChild(nodeName) != null) {
            LOG.debug(
                "Navigation node named " + nodeName + " already exist, will not add it anymore");
          } else {
            rootNode.addChild(index, nodeName);
            index++;
          }
        }
        navService.saveNode(rootNode.context, null);
      }
    }
  }

  /**
   * @param navType
   * @param navOwner
   * @param absolutePath path from root to targeted node
   * @param nodePrefix
   * @param startIndex
   * @param endIndex
   */
  public void addNodes(
      String navType,
      String navOwner,
      String absolutePath,
      String nodePrefix,
      int startIndex,
      int endIndex) {
    SiteKey key = new SiteKey(navType, navOwner);
    NavigationContext navCtx = navService.loadNavigation(key);
    if (navCtx == null) {
      LOG.error("Navigation type= " + navType + " , owner= " + navOwner + " does not exist");
    } else {
      String[] path = absolutePath.split("/");
      NavNode rootNode =
          navService
              .loadNode(new NavNodeModel(), navCtx, GenericScope.branchShape(path), null)
              .getNode();
      NavNode targetNode = rootNode.getDescendant(path);
      if (targetNode == null) {
        LOG.error(
            "Could not find node specified by path "
                + absolutePath
                + " under navigation type= "
                + navType
                + " , owner= "
                + navOwner);
      } else {
        int index = targetNode.getSize();
        for (int i = startIndex; i < endIndex; i++) {
          String nodeName = nodePrefix + "_" + i;
          if (targetNode.getChild(nodeName) == null) {
            targetNode.addChild(index, nodeName);
            index++;
          }
        }
        navService.saveNode(targetNode.context, null);
      }
    }
  }

  @Managed
  @ManagedDescription("Create new navigation")
  @Impact(ImpactType.READ)
  public void createNavs(
      @ManagedDescription("Type of new navigation") @ManagedName("navType") String type,
      @ManagedDescription("Owner of new navigation") @ManagedName("navOwner") String owner,
      @ManagedDescription("Prefix of new node names") @ManagedName("prefix") String prefix,
      @ManagedDescription("Starting index") @ManagedName("startIndex") String startIndex,
      @ManagedDescription("Ending index") @ManagedName("endIndex") String endIndex) {
    int _startIndex = Integer.parseInt(startIndex);
    int _endIndex = Integer.parseInt(endIndex);
    // Invoke from JMX bean will not go through GateIn's servlet filter. Therefore, we need to
    // open/close transaction
    try {
      startTransaction();
      createNavigation(type, owner, prefix, _startIndex, _endIndex);
    } catch (Exception ex) {
      LOG.error("Failed to create new navigation", ex);
    } finally {
      endTransaction();
    }
  }

  @Managed
  @ManagedDescription("Add nodes into root node of existing navigation")
  @Impact(ImpactType.READ)
  public void insertNodes(
      @ManagedDescription("Type of target navigation") @ManagedName("navType") String navType,
      @ManagedDescription("Owner of target navigation") @ManagedName("navOwner") String navOwner,
      @ManagedDescription("Prefix of new node names") @ManagedName("prefix") String nodePrefix,
      @ManagedDescription("Starting index") @ManagedName("startIndex") String startIndex,
      @ManagedDescription("Ending index") @ManagedName("endIndex") String endIndex) {
    int _startIndex = Integer.parseInt(startIndex);
    int _endIndex = Integer.parseInt(endIndex);
    // Invoke from JMX bean will not go through GateIn's servlet filter. Therefore, we need to
    // open/close transaction
    try {
      startTransaction();
      addNodes(navType, navOwner, nodePrefix, _startIndex, _endIndex);
    } catch (Exception ex) {
      LOG.error("Failed to insert new nodes", ex);
    } finally {
      endTransaction();
    }
  }

  @Managed
  @ManagedDescription("Add nodes into node specified by path in existing navigation")
  @Impact(ImpactType.READ)
  public void insertNodes(
      @ManagedDescription("Type of target navigation") @ManagedName("navType") String navType,
      @ManagedDescription("Owner of target navigation") @ManagedName("navOwner") String navOwner,
      @ManagedDescription("Path from root to target node") @ManagedName("absolutePath")
          String absolutePath,
      @ManagedDescription("Prefix of new node names") @ManagedName("prefix") String nodePrefix,
      @ManagedDescription("Starting index") @ManagedName("startIndex") String startIndex,
      @ManagedDescription("Ending index") @ManagedName("endIndex") String endIndex) {
    int _startIndex = Integer.parseInt(startIndex);
    int _endIndex = Integer.parseInt(endIndex);
    // Invoke from JMX bean will not go through GateIn's servlet filter. Therefore, we need to
    // open/close transaction
    try {
      startTransaction();
      addNodes(navType, navOwner, absolutePath, nodePrefix, _startIndex, _endIndex);
    } catch (Exception ex) {
      LOG.error("Failed to insert new nodes", ex);
    } finally {
      endTransaction();
    }
  }

  @Managed
  @ManagedDescription("Delete node specified by path in existing navigation")
  @Impact(ImpactType.READ)
  public void deleteNode(
      @ManagedDescription("Type of target navigation") @ManagedName("navType") String navType,
      @ManagedDescription("Owner of target navigation") @ManagedName("navOwner") String navOwner,
      @ManagedDescription("Path from root to target node") @ManagedName("pathFromRoot")
          String pathFromRoot) {
    try {
      startTransaction();
      NavigationContext ctx = navService.loadNavigation(new SiteKey(navType, navOwner));
      if (ctx == null) {
        LOG.error("Navigation type= " + navType + " , owner= " + navOwner + " does not exist");
      } else {
        String[] path = pathFromRoot.split("/");
        NavNode rootNode =
            navService
                .loadNode(new NavNodeModel(), ctx, GenericScope.branchShape(path), null)
                .getNode();
        NavNode targetNode = rootNode.getDescendant(path);
        if (targetNode != null && targetNode != rootNode) {
          targetNode.remove();
        }
      }
    } finally {
      endTransaction();
    }
  }
}
/** @author <a href="mailto:[email protected]">Peter Palaga</a> */
public class GateInResourcesDeployer implements WebAppListener {
  private static final Logger log = LoggerFactory.getLogger(GateInResourcesDeployer.class);

  /** Path to {@code gatein-resources.xml} */
  public static final String GATEIN_CONFIG_RESOURCE = "/WEB-INF/gatein-resources.xml";

  /**
   * A key used to store a collection of JavaScript resources loaded from a given servlet context.
   */
  public static final String SCRIPT_RESOURCES_ATTR = "gatein.script.resources";

  /** The {@link SkinService} */
  private final SkinService skinService;

  /** The {@link JavascriptConfigService} */
  private final JavascriptConfigService javascriptConfigService;

  /** The name of the portal container */
  private final String portalContainerName;

  /**
   * @param portalContainerName
   * @param skinService
   * @param javascriptConfigService
   */
  public GateInResourcesDeployer(
      String portalContainerName,
      SkinService skinService,
      JavascriptConfigService javascriptConfigService) {
    super();
    this.portalContainerName = portalContainerName;
    this.skinService = skinService;
    this.javascriptConfigService = javascriptConfigService;
  }

  /** @see org.gatein.wci.WebAppListener#onEvent(org.gatein.wci.WebAppEvent) */
  public void onEvent(WebAppEvent event) {
    if (event instanceof WebAppLifeCycleEvent) {
      WebAppLifeCycleEvent lifeCycleEvent = (WebAppLifeCycleEvent) event;
      WebApp webApp = null;
      URL url = null;
      switch (lifeCycleEvent.getType()) {
        case WebAppLifeCycleEvent.ADDED:
          webApp = event.getWebApp();
          url = getGateinResourcesXml(webApp);
          if (url != null) {
            add(webApp, url);
          }
          break;
        case WebAppLifeCycleEvent.REMOVED:
          webApp = event.getWebApp();
          url = getGateinResourcesXml(webApp);
          if (url != null) {
            remove(event.getWebApp());
          }
          break;
      }
    }
  }

  /**
   * Called on web application add event if the application contains {@value
   * #GATEIN_CONFIG_RESOURCE} file.
   *
   * @param webApp
   * @param url
   */
  protected void add(final WebApp webApp, final URL url) {

    ServletContext scontext = webApp.getServletContext();
    try {
      /* Validate straight away here before creating the PortalContainerPostInitTask */
      final Document document = GateInResourcesSchemaValidator.validate(url);
      /* Also parse both js and skin resources before creating the PortalContainerPostInitTask */
      final ScriptResources scriptResources =
          new JavascriptConfigParser(scontext, document).parse();
      final List<SkinConfigTask> skinTasks = SkinConfigParser.parse(document);

      /* No exceptions at this point */
      final PortalContainerPostInitTask task =
          new PortalContainerPostInitTask() {
            public void execute(ServletContext scontext, PortalContainer portalContainer) {

              try {

                if (!scriptResources.isEmpty()) {
                  javascriptConfigService.add(scriptResources);
                  scontext.setAttribute(SCRIPT_RESOURCES_ATTR, scriptResources.toImmutable());
                }
                javascriptConfigService.registerContext(webApp);

                if (skinTasks != null && !skinTasks.isEmpty()) {
                  skinService.addSkins(skinTasks, scontext);
                }
                skinService.registerContext(webApp);

              } catch (Exception e) {
                log.error(
                    "Could not register script and skin resources from the context '"
                        + (scontext == null ? "unknown" : scontext.getServletContextName())
                        + "'",
                    e);

                /* try to cleanup if anything went wrong */
                try {
                  remove(webApp);
                } catch (Exception e1) {
                  log.error(
                      "Could not cleanup script and skin resources from the context '"
                          + (scontext == null ? "unknown" : scontext.getServletContextName())
                          + "' after a registration failure",
                      e);
                }
              }
            }
          };
      PortalContainer.addInitTask(scontext, task, portalContainerName);
    } catch (Exception ex) {
      log.error(
          "Could not parse or validate gatein-resources.xml in context '"
              + (scontext == null ? "unknown" : scontext.getServletContextName())
              + "'",
          ex);
    }
  }

  /**
   * Called on web application remove event if the application contains {@value
   * #GATEIN_CONFIG_RESOURCE} file.
   *
   * @param webApp
   */
  protected void remove(WebApp webApp) {
    String contextPath = webApp.getServletContext().getContextPath();
    javascriptConfigService.unregisterServletContext(webApp);
    try {
      javascriptConfigService.remove(contextPath);
    } catch (Exception ex) {
      log.error(
          "An error occurred while removing script resources for the context '"
              + webApp.getServletContext().getServletContextName()
              + "'",
          ex);
    }

    try {
      skinService.removeSkins(SkinDependentManager.getPortalSkins(contextPath));
      skinService.removeSkins(SkinDependentManager.getPortletSkins(contextPath));

      /*
       * Remove skinName defined by the webApp, if no other webApps supports the skinName
       */
      Set<String> supportedSkins = SkinDependentManager.getSkinNames(contextPath);
      if (supportedSkins != null) {
        for (String skin : supportedSkins) {
          if (SkinDependentManager.skinNameIsRemovable(skin, contextPath)) {
            skinService.removeSupportedSkin(skin);
          }
        }
      }

      // Update the 'skinDependentManager'
      SkinDependentManager.clearAssociatedSkins(contextPath);
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
    skinService.unregisterServletContext(webApp);
  }

  static URL getGateinResourcesXml(final WebApp webApp) {
    try {
      return webApp.getServletContext().getResource(GATEIN_CONFIG_RESOURCE);
    } catch (MalformedURLException e) {
      throw new RuntimeException(e);
    }
  }
}
/**
 * The PortalContainer servlet is the main entry point for the eXo Portal product.
 *
 * <p>Both the init() and service() methods are implemented. The first one is used to configure all
 * the portal resources to prepare the platform to receive requests. The second one is used to
 * handle them.
 *
 * <p>Basically, this class is just dispatcher as the real business logic is implemented inside the
 * WebAppController class.
 */
@SuppressWarnings("serial")
public class PortalController extends AbstractHttpServlet {

  protected static Logger log =
      LoggerFactory.getLogger("org.gatein.portal.application.PortalController");

  /**
   * The onInit() method is used to prepare the portal to receive requests.
   *
   * <p>1) Get the WebAppController component from the container 2) Create a new PortalApplication,
   * init it with the ServletConfig object (which contains init params) 3) Register that
   * PortalApplication inside WebAppController 4) Create a new PortalRequestHandler object and
   * register it in the WebAppController
   */
  private void onInit(ServletConfig sConfig, PortalContainer portalContainer) {
    // Keep the old ClassLoader
    final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
    boolean hasChanged = false;
    try {
      ServletConfig config = new PortalServletConfig(sConfig, portalContainer);
      WebAppController controller =
          (WebAppController) portalContainer.getComponentInstanceOfType(WebAppController.class);
      // Set the full classloader of the portal container
      Thread.currentThread().setContextClassLoader(portalContainer.getPortalClassLoader());
      hasChanged = true;

      controller.onHandlersInit(config);
      log.info(
          "The WebAppController has been successfully initialized for the portal '"
              + portalContainer.getName()
              + "'");
    } catch (Throwable t) {
      log.error(
          "The WebAppController could not be initialized for the portal '"
              + portalContainer.getName()
              + "'",
          t);
    } finally {
      if (hasChanged) {
        // Re-set the old classloader
        Thread.currentThread().setContextClassLoader(currentClassLoader);
      }
    }
  }

  /**
   * @see org.exoplatform.container.web.AbstractHttpServlet#afterInit(javax.servlet.ServletConfig)
   */
  public void afterInit(final ServletConfig config) throws ServletException {
    final PortalContainerPostCreateTask task =
        new PortalContainerPostCreateTask() {

          public void execute(ServletContext context, PortalContainer portalContainer) {
            onInit(config, portalContainer);
          }
        };
    ServletContext context = config.getServletContext();
    RootContainer rootContainer = RootContainer.getInstance();
    rootContainer.addInitTask(context, task);
    rootContainer.registerPortalContainer(context);
  }

  /**
   * This method simply delegates the incoming call to the WebAppController stored in the Portal
   * Container object
   */
  @Override
  protected void onService(ExoContainer container, HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
    try {
      WebAppController controller =
          (WebAppController) container.getComponentInstanceOfType(WebAppController.class);
      controller.service(req, res);
    } catch (Throwable t) {
      throw new ServletException(t);
    }
  }

  /** @see org.exoplatform.container.web.AbstractHttpServlet#requirePortalEnvironment() */
  @Override
  protected boolean requirePortalEnvironment() {
    return true;
  }

  private static class PortalServletConfig implements ServletConfig {
    private final ServletConfig sConfig;

    private final PortalContainer portalContainer;

    public PortalServletConfig(ServletConfig sConfig, PortalContainer portalContainer) {
      this.sConfig = sConfig;
      this.portalContainer = portalContainer;
    }

    public String getServletName() {
      return sConfig.getServletName();
    }

    public ServletContext getServletContext() {
      return portalContainer.getPortalContext();
    }

    @SuppressWarnings("unchecked")
    public Enumeration getInitParameterNames() {
      return sConfig.getInitParameterNames();
    }

    public String getInitParameter(String name) {
      return sConfig.getInitParameter(name);
    }
  }
}
/** @author <a href="mailto:[email protected]">Julien Viet</a> */
public class ResourceRequestHandler extends WebRequestHandler {

  public static final String IF_MODIFIED_SINCE = "If-Modified-Since";

  public static final String LAST_MODIFIED = "Last-Modified";

  /** . */
  private static String PATH =
      "META-INF/maven/org.exoplatform.portal/exo.portal.component.web.resources/pom.properties";

  /** . */
  private static final Logger log = LoggerFactory.getLogger(ResourceRequestHandler.class);

  /** . */
  public static final String VERSION;

  static {
    // Detecting version from maven properties
    // empty value is ok
    String version = "";
    URL url = ResourceRequestHandler.class.getClassLoader().getResource(PATH);
    if (url != null) {
      log.debug("Loading resource serving version from " + url);
      InputStream in = null;
      try {
        in = url.openStream();
        Properties props = new Properties();
        props.load(in);
        version = props.getProperty("version");
      } catch (IOException e) {
        log.error("Could not read properties from " + url, e);
      } finally {
        IOTools.safeClose(in);
      }
    }

    //
    log.info("Use version \"" + version + "\" for resource serving");
    VERSION = version;
  }

  /** . */
  public static final QualifiedName VERSION_QN = QualifiedName.create("gtn", "version");

  /** . */
  public static final QualifiedName RESOURCE_QN = QualifiedName.create("gtn", "resource");

  /** . */
  public static final QualifiedName SCOPE_QN = QualifiedName.create("gtn", "scope");

  /** . */
  public static final QualifiedName MODULE_QN = QualifiedName.create("gtn", "module");

  /** . */
  public static final QualifiedName COMPRESS_QN = QualifiedName.create("gtn", "compress");

  /** . */
  public static final QualifiedName LANG_QN = QualifiedName.create("gtn", "lang");

  /** . */
  private final FutureMap<ScriptKey, ScriptResult, ControllerContext> cache;

  public ResourceRequestHandler() {
    this.cache = new FutureMap<ScriptKey, ScriptResult, ControllerContext>(new ScriptLoader());
  }

  @Override
  public String getHandlerName() {
    return "script";
  }

  @Override
  public boolean execute(ControllerContext context) throws Exception {
    String resourceParam = context.getParameter(RESOURCE_QN);
    String scopeParam = context.getParameter(SCOPE_QN);

    //
    if (scopeParam != null && resourceParam != null) {
      String compressParam = context.getParameter(COMPRESS_QN);
      String lang = context.getParameter(LANG_QN);
      String moduleParam = context.getParameter(MODULE_QN);

      //
      Locale locale = null;
      if (lang != null && lang.length() > 0) {
        locale = I18N.parseTagIdentifier(lang);
      }

      //
      ResourceScope scope;
      try {
        scope = ResourceScope.valueOf(ResourceScope.class, scopeParam);
      } catch (IllegalArgumentException e) {
        HttpServletResponse response = context.getResponse();
        String msg = "Unrecognized scope " + scopeParam;
        log.error(msg);
        response.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        return true;
      }

      //
      ResourceId resource = new ResourceId(scope, resourceParam);

      ScriptKey key = new ScriptKey(resource, moduleParam, "min".equals(compressParam), locale);

      //
      ScriptResult result = cache.get(context, key);
      HttpServletResponse response = context.getResponse();
      HttpServletRequest request = context.getRequest();

      //
      if (result instanceof ScriptResult.Resolved) {
        ScriptResult.Resolved resolved = (ScriptResult.Resolved) result;

        // Content type + charset
        response.setContentType("text/javascript");
        response.setCharacterEncoding("UTF-8");

        // One hour caching
        // make this configurable later
        response.setHeader("Cache-Control", "max-age:3600");
        response.setDateHeader("Expires", System.currentTimeMillis() + 3600 * 1000);

        // Set content length
        response.setContentLength(resolved.bytes.length);

        long ifModifiedSince = request.getDateHeader(IF_MODIFIED_SINCE);
        if (resolved.isModified(ifModifiedSince)) {
          response.setDateHeader(ResourceRequestFilter.LAST_MODIFIED, resolved.lastModified);
          // Send bytes
          ServletOutputStream out = response.getOutputStream();
          try {
            out.write(resolved.bytes);
          } finally {
            Safe.close(out);
          }
        } else {
          response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
        }
      } else if (result instanceof ScriptResult.Error) {
        ScriptResult.Error error = (ScriptResult.Error) result;
        log.error("Could not render script " + key + "\n:" + error.message);
        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      } else {
        String msg = "Resource " + key + " cannot be found";
        log.error(msg);
        response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);
      }
    } else {
      HttpServletResponse response = context.getResponse();
      String msg = "Missing scope or resource param";
      log.error(msg);
      response.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }

    //
    return true;
  }

  @Override
  protected boolean getRequiresLifeCycle() {
    return false;
  }
}
/**
 * @author <a href="mailto:[email protected]">Chris Laprun</a>
 * @version $Revision$
 */
public class RegistrationCheckingPortletInvoker extends PortletInvokerInterceptor
    implements RegistrationDestructionListener {
  /** Registration Manager */
  private RegistrationManager registrationManager;

  private static final Logger log =
      LoggerFactory.getLogger(RegistrationCheckingPortletInvoker.class);

  public void setRegistrationManager(RegistrationManager registrationManager) {
    this.registrationManager = registrationManager;
    registrationManager.addRegistrationDestructionListener(this);
  }

  private RegistrationPolicy getPolicy() {
    return registrationManager.getPolicy();
  }

  public Portlet getPortlet(PortletContext portletContext)
      throws IllegalArgumentException, PortletInvokerException {
    if (isPortletContextKnown(portletContext)) {
      return super.getPortlet(portletContext);
    } else {
      throw new NoSuchPortletException(portletContext.getId());
    }
  }

  private boolean isPortletContextKnown(PortletContext portletContext)
      throws PortletInvokerException {
    final PortletStatus status = super.getStatus(portletContext);
    if (PortletStatus.OFFERED == status) {
      return true;
    } else {
      Registration registration = RegistrationLocal.getRegistration();
      if (registration != null) {
        if (registration.knows(portletContext)) {
          return true;
        } else {
          String id = portletContext.getId();
          throw new NoSuchPortletException(
              "Registration '"
                  + registration.getRegistrationHandle()
                  + "' does not know the '"
                  + id
                  + "' portlet",
              id);
        }
      } else {
        return status != null;
      }
    }
  }

  public Set<Portlet> getPortlets() throws PortletInvokerException {
    Set<Portlet> portlets = new HashSet<Portlet>(super.getPortlets());
    Registration registration = RegistrationLocal.getRegistration();

    if (registration != null) {
      Set<PortletContext> contexts = registration.getKnownPortletContexts();
      for (PortletContext context : contexts) {
        try {
          portlets.add(super.getPortlet(context));
        } catch (NoSuchPortletException e) {
          final RegistrationSPI registrationSPI = getRegistrationAsSPI();
          try {
            registrationSPI.removePortletContext(context);
            log.debug(
                "Removed '"
                    + context
                    + "' from Registration '"
                    + registration.getRegistrationHandle()
                    + "' because it cannot be resolved anymore.");
          } catch (RegistrationException e1) {
            throw new PortletInvokerException(e1);
          }
        }
      }
    }

    return portlets;
  }

  private RegistrationSPI getRegistrationAsSPI() throws PortletInvokerException {
    Registration registration = RegistrationLocal.getRegistration();

    if (registration == null) {
      return null;
    }

    if (registration instanceof RegistrationSPI) {
      return (RegistrationSPI) registration;
    } else {
      throw new PortletInvokerException("Cannot deal with non-RegistrationSPI Registrations.");
    }
  }

  public PortletInvocationResponse invoke(PortletInvocation invocation)
      throws IllegalArgumentException, PortletInvokerException {
    PortletContext portletContext = invocation.getTarget();

    RegistrationSPI registration = getRegistrationAsSPI();

    if (registration != null) {
      checkOperationIsAllowed(portletContext, registration, "invoke");

      PortletInvocationResponse response = super.invoke(invocation);

      InstanceContext instanceContext = invocation.getInstanceContext();
      if (instanceContext instanceof WSRPInstanceContext) {
        WSRPInstanceContext wsrpIC = (WSRPInstanceContext) instanceContext;
        PortletContext responseContext = wsrpIC.getPortletContext();
        if (wsrpIC.wasModified() && !responseContext.getId().equals(portletContext.getId())) {
          try {
            registration.addPortletContext(responseContext);
          } catch (RegistrationException e) {
            throw new PortletInvokerException(
                "Couldn't add portlet context '"
                    + responseContext
                    + "' to registration '"
                    + registration.getRegistrationHandle()
                    + "'",
                e);
          }
        }
      }

      return response;
    } else {
      return super.invoke(invocation);
    }
  }

  private void checkOperationIsAllowed(
      PortletContext portletContext, Registration registration, String operation)
      throws NoSuchPortletException {
    if (!getPolicy().allowAccessTo(portletContext, registration, operation)) {
      String id = portletContext.getId();
      throw new NoSuchPortletException(
          "The PortletContext '"
              + id
              + "' does not exist or the application is lacking permission to access it for operation '"
              + operation
              + "'",
          id);
    }
  }

  public PortletContext createClone(PortletStateType stateType, PortletContext portletContext)
      throws IllegalArgumentException, PortletInvokerException, UnsupportedOperationException {
    RegistrationSPI registration = getRegistrationAsSPI();

    if (registration != null) {
      checkOperationIsAllowed(portletContext, registration, "createClone");

      PortletContext clonedPortletContext = super.createClone(stateType, portletContext);
      try {
        registration.addPortletContext(clonedPortletContext);
      } catch (RegistrationException e) {
        throw new PortletInvokerException(
            "Couldn't add portlet context '"
                + clonedPortletContext
                + "' to registration '"
                + registration.getRegistrationHandle()
                + "'",
            e);
      }

      return clonedPortletContext;
    } else {
      return super.createClone(stateType, portletContext);
    }
  }

  public List<DestroyCloneFailure> destroyClones(List<PortletContext> portletContexts)
      throws IllegalArgumentException, PortletInvokerException, UnsupportedOperationException {
    RegistrationSPI registration = getRegistrationAsSPI();

    if (registration != null) {
      for (PortletContext portletContext : portletContexts) {
        checkOperationIsAllowed(portletContext, registration, "destroyClones");
      }
    }

    List<DestroyCloneFailure> cloneFailures = super.destroyClones(portletContexts);
    boolean noFailures = cloneFailures.isEmpty();

    if (registration != null) {
      for (PortletContext portletContext : portletContexts) {
        // only remove the portlet context if there are no failures or it's not part of the failed
        // clones
        if (noFailures
            || !cloneFailures.contains(new DestroyCloneFailure(portletContext.getId()))) {
          try {
            registration.removePortletContext(portletContext);
          } catch (RegistrationException e) {
            throw new PortletInvokerException(
                "Couldn't remove portlet context '"
                    + portletContext
                    + "' to registration '"
                    + registration.getRegistrationHandle()
                    + "'",
                e);
          }
        }
      }
    }

    return cloneFailures;
  }

  public PropertyMap getProperties(PortletContext portletContext)
      throws IllegalArgumentException, PortletInvokerException, UnsupportedOperationException {
    checkOperationIsAllowed(portletContext, RegistrationLocal.getRegistration(), "getProperties");
    return super.getProperties(portletContext);
  }

  public PropertyMap getProperties(PortletContext portletContext, Set<String> keys)
      throws IllegalArgumentException, PortletInvokerException, UnsupportedOperationException {
    checkOperationIsAllowed(portletContext, RegistrationLocal.getRegistration(), "getProperties");
    return super.getProperties(portletContext, keys);
  }

  public PortletContext setProperties(PortletContext portletContext, PropertyChange[] changes)
      throws IllegalArgumentException, PortletInvokerException, UnsupportedOperationException {
    RegistrationSPI registration = getRegistrationAsSPI();

    if (registration != null) {
      checkOperationIsAllowed(portletContext, registration, "setProperties");
      PortletContext updatedPortletContext = super.setProperties(portletContext, changes);

      if (!portletContext.getId().equals(updatedPortletContext.getId())) {
        try {
          registration.addPortletContext(updatedPortletContext);
        } catch (RegistrationException e) {
          throw new PortletInvokerException(
              "Couldn't add portlet context '"
                  + updatedPortletContext
                  + "' to registration '"
                  + registration.getRegistrationHandle()
                  + "'",
              e);
        }
      }

      return updatedPortletContext;
    } else {
      return super.setProperties(portletContext, changes);
    }
  }

  public PortletContext importPortlet(
      PortletStateType stateType, PortletContext originalPortletContext)
      throws PortletInvokerException, IllegalArgumentException {
    // The original portletcontext is the non cloned version and should be one the PC available from
    // the getPortlets operation
    RegistrationSPI registration = getRegistrationAsSPI();

    if (registration != null) {
      checkOperationIsAllowed(originalPortletContext, registration, "importPortlet");

      PortletContext newPortletContext = super.importPortlet(stateType, originalPortletContext);

      if (!newPortletContext.getId().equals(originalPortletContext.getId())) {
        try {
          registration.addPortletContext(newPortletContext);
        } catch (RegistrationException e) {
          throw new PortletInvokerException(
              "Couldn't add portlet context '"
                  + newPortletContext
                  + "' to registration '"
                  + registration.getRegistrationHandle()
                  + "'",
              e);
        }
      }

      return newPortletContext;
    } else {
      return super.importPortlet(stateType, originalPortletContext);
    }
  }

  public PortletContext exportPortlet(PortletStateType stateType, PortletContext portletContext)
      throws PortletInvokerException, IllegalArgumentException {
    if (isPortletContextKnown(portletContext)) {
      checkOperationIsAllowed(portletContext, RegistrationLocal.getRegistration(), "exportPortlet");
      return super.exportPortlet(stateType, portletContext);
    } else {
      throw new NoSuchPortletException(portletContext.getId());
    }
  }

  /**
   * Destroy the clones scoped by this Registration.
   *
   * @param registration the Registration about to be destroyed
   * @return
   */
  public Vote destructionScheduledFor(Registration registration) {
    if (registration != null) {
      List<PortletContext> portletContexts =
          new ArrayList<PortletContext>(registration.getKnownPortletContexts());
      List<DestroyCloneFailure> failures = Collections.emptyList();
      try {
        failures = super.destroyClones(portletContexts);
      } catch (Exception e) {
        if (log.isDebugEnabled()) {
          log.debug("Couldn't destroy clones", e);
        }
        return Vote.negativeVote("Couldn't destroy clones: " + failures);
      }
    }

    return RegistrationDestructionListener.SUCCESS;
  }
}
/**
 * @author <a href="mailto:[email protected]">Julien Viet</a>
 * @version $Revision$
 */
public class PortletApplicationMetaDataBuilder {

  /** . */
  private static final Logger log =
      LoggerFactory.getLogger(PortletApplicationMetaDataBuilder.class);

  /** . */
  private static final QName XML_LANG = new QName("http://www.w3.org/XML/1998/namespace", "lang");

  /** . */
  private static final String PORTLET_1_0 =
      "http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd";

  /** . */
  private static final String PORTLET_2_0 =
      "http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd";

  /** . */
  private static final EnumSet<Element> NAME_OR_QNAME = EnumSet.of(Element.name, Element.qname);

  /** . */
  private static final ValueType<PortletCacheScopeEnum> PORTLET_CACHE_SCOPE =
      ValueType.get(PortletCacheScopeEnum.class);

  /** . */
  private static final ValueType<TransportGuarantee> TRANSPORT_GUARANTEE =
      ValueType.get(TransportGuarantee.class);

  /** . */
  private static final ValueType<LifeCyclePhase> LIFE_CYCLE =
      new ValueType<LifeCyclePhase>() {
        @Override
        protected LifeCyclePhase parse(String s) throws Exception {
          if (s.endsWith("_PHASE")) {
            return LifeCyclePhase.valueOf(s.substring(0, s.length() - 6));
          } else {
            throw new IllegalArgumentException("Value " + s + " is not legal");
          }
        }
      };

  /** . */
  private boolean schemaValidation;

  /** . */
  private XMLInputFactory inputFactory;

  public PortletApplicationMetaDataBuilder() {
    this(XMLInputFactory.newInstance(), false);
  }

  public PortletApplicationMetaDataBuilder(XMLInputFactory inputFactory, boolean schemaValidation)
      throws NullPointerException {
    if (inputFactory == null) {
      throw new NullPointerException("No null xml input factory allowed");
    }

    //
    this.inputFactory = inputFactory;
    this.schemaValidation = schemaValidation;
  }

  public boolean getSchemaValidation() {
    return schemaValidation;
  }

  public void setSchemaValidation(boolean schemaValidation) {
    this.schemaValidation = schemaValidation;
  }

  public PortletApplication20MetaData build(InputStream is) throws DeploymentException {

    // We will need to read the input stream twice
    byte[] bytes = null;
    if (schemaValidation) {
      try {
        bytes = IOTools.getBytes(is);
        is = new ByteArrayInputStream(bytes);
      } catch (IOException e) {
        throw new DeploymentException("Could not read portlet.xml descriptor", e);
      }
    }

    PortletApplication20MetaData md = new PortletApplication20MetaData();

    //
    inputFactory.setProperty("javax.xml.stream.isCoalescing", true);
    StaxNavigator<Element> nav = null;
    try {
      XMLStreamReader stream = inputFactory.createXMLStreamReader(is);
      nav =
          StaxNavigatorFactory.create(
              new Naming.Enumerated.Simple<Element>(Element.class, null), stream);
    } catch (XMLStreamException e) {
      throw new DeploymentException("Could not create a STAX reader", e);
    }

    // We want to trim content (mandated by the spec)
    nav.setTrimContent(true);

    // Get the root element qname
    QName qname = nav.getQName();
    String rootNS = qname.getNamespaceURI();

    // Determine the correct version to parse
    int version;
    if (PORTLET_1_0.equals(rootNS)) {
      md.setVersion("1.0");
      version = 1;
    } else if (PORTLET_2_0.equals(rootNS)) {
      md.setVersion("2.0");
      version = 2;
    } else {
      throw new StaxNavException("Illegal portlet xml namespace " + rootNS);
    }

    // Perform schema validation if required
    if (schemaValidation) {
      XSD xsd = version == 1 ? XSD.PORTLET_1_0 : XSD.PORTLET_2_0;
      try {
        xsd.validate(new StreamSource(new ByteArrayInputStream(bytes)));
      } catch (Exception e) {
        throw new DeploymentException("The portlet.xml file is not valid XML", e);
      }
    }

    //
    assert Element.portlet_app == nav.getName();

    //
    if (nav.child() == null) {
      return md;
    }

    //
    for (StaxNavigator<Element> portletNav : nav.fork(Element.portlet)) {
      PortletMetaData portletMD = new PortletMetaData();

      //
      portletMD.setId(portletNav.getAttribute("id"));
      portletMD.setDescription(readLocalizedString(portletNav, Element.description));
      portletMD.setPortletName(getContent(portletNav, Element.portlet_name));
      portletMD.setDisplayName(readLocalizedString(portletNav, Element.display_name));
      portletMD.setPortletClass(getContent(portletNav, Element.portlet_class));

      //
      for (InitParamMetaData initParamMD : readInitParams(portletNav)) {
        portletMD.addInitParam(initParamMD);
      }

      //
      if (portletNav.next(Element.expiration_cache)) {
        portletMD.setExpirationCache(Integer.parseInt(portletNav.getContent()));
      }
      if (portletNav.next(Element.cache_scope)) {
        portletMD.setCacheScope(PortletCacheScopeEnum.valueOf(portletNav.getContent()));
      }

      //
      while (portletNav.next(Element.supports)) {
        SupportsMetaData supportsMD = new SupportsMetaData();
        supportsMD.setId(portletNav.getAttribute("id"));
        supportsMD.setMimeType(getContent(portletNav, Element.mime_type));
        while (portletNav.next(Element.portlet_mode)) {
          PortletModeMetaData portletModeMD = new PortletModeMetaData();
          portletModeMD.setPortletMode(Mode.create(portletNav.getContent()));
          supportsMD.addPortletMode(portletModeMD);
        }
        while (portletNav.next(Element.window_state)) {
          WindowStateMetaData windowStateMD = new WindowStateMetaData();
          windowStateMD.setWindowState(WindowState.create(portletNav.getContent()));
          supportsMD.addWindowState(windowStateMD);
        }
        portletMD.addSupport(supportsMD);
      }

      //
      while (portletNav.next(Element.supported_locale)) {
        SupportedLocaleMetaData supportedLocaleMD = new SupportedLocaleMetaData();
        supportedLocaleMD.setLocale(portletNav.getContent());
        portletMD.addSupportedLocale(supportedLocaleMD);
      }
      if (portletNav.next(Element.resource_bundle)) {
        portletMD.setResourceBundle(portletNav.getContent());
      }

      //
      if (portletNav.next(Element.portlet_info)) {
        PortletInfoMetaData portletInfoMD = new PortletInfoMetaData();
        if (portletNav.next(Element.title)) {
          portletInfoMD.setTitle(portletNav.getContent());
        }
        if (portletNav.next(Element.short_title)) {
          portletInfoMD.setShortTitle(portletNav.getContent());
        }
        if (portletNav.next(Element.keywords)) {
          portletInfoMD.setKeywords(portletNav.getContent());
        }
        portletMD.setPortletInfo(portletInfoMD);
      }

      //
      if (portletNav.next(Element.portlet_preferences)) {
        PortletPreferencesMetaData portletPreferencesMD = new PortletPreferencesMetaData();
        while (portletNav.next(Element.preference)) {
          PortletPreferenceMetaData portletPreferenceMD = new PortletPreferenceMetaData();
          portletPreferenceMD.setName(getContent(portletNav, Element.name));
          while (portletNav.next(Element.value)) {
            portletPreferenceMD.addValue(portletNav.getContent());
          }
          if (portletNav.next(Element.read_only)) {
            portletPreferenceMD.setReadOnly(portletNav.parseContent(ValueType.BOOLEAN));
          }
          portletPreferencesMD.addPortletPreference(portletPreferenceMD);
        }
        if (portletNav.next(Element.preferences_validator)) {
          portletPreferencesMD.setPreferenceValidator(portletNav.getContent());
        }
        portletMD.setPortletPreferences(portletPreferencesMD);
      }

      //
      while (portletNav.next(Element.security_role_ref)) {
        SecurityRoleRefMetaData securityRoleRefMD = new SecurityRoleRefMetaData();
        securityRoleRefMD.setDescription(readLocalizedString(portletNav, Element.description));
        securityRoleRefMD.setRoleName(getContent(portletNav, Element.role_name));
        if (portletNav.next(Element.role_link)) {
          securityRoleRefMD.setRoleLink(portletNav.getContent());
        }
        portletMD.addSecurityRoleRef(securityRoleRefMD);
      }

      //
      while (portletNav.next(Element.supported_processing_event)
          || portletNav.next(Element.supported_publishing_event)) {
        boolean processing = portletNav.getName() == Element.supported_processing_event;
        EventDefinitionReferenceMetaData eventDefinitionReferenceMD =
            new EventDefinitionReferenceMetaData();
        switch (portletNav.next(NAME_OR_QNAME)) {
          case name:
            eventDefinitionReferenceMD.setName(portletNav.getContent());
            break;
          case qname:
            eventDefinitionReferenceMD.setQname(readQName(portletNav));
            break;
        }
        if (processing) {
          portletMD.addSupportedProcessingEvent(eventDefinitionReferenceMD);
        } else {
          portletMD.addSupportedPublishingEvent(eventDefinitionReferenceMD);
        }
      }
      while (portletNav.next(Element.supported_public_render_parameter)) {
        portletMD.addSupportedPublicRenderParameter(portletNav.getContent());
      }
      while (portletNav.next(Element.container_runtime_option)) {
        ContainerRuntimeMetaData containerRuntimeOptionMD = new ContainerRuntimeMetaData();
        containerRuntimeOptionMD.setName(getContent(portletNav, Element.name));
        while (portletNav.next(Element.value)) {
          containerRuntimeOptionMD.addValue(portletNav.getContent());
        }
        portletMD.addContainerRuntime(containerRuntimeOptionMD);
      }

      //
      md.addPortlet(portletMD);
    }

    //
    for (StaxNavigator<Element> customPortletModeNav : nav.fork(Element.custom_portlet_mode)) {
      CustomPortletModeMetaData customPortletModeMD = new CustomPortletModeMetaData();
      customPortletModeMD.setId(customPortletModeNav.getAttribute("id"));
      customPortletModeMD.setDescription(
          readLocalizedString(customPortletModeNav, Element.description));
      customPortletModeMD.setPortletMode(getContent(customPortletModeNav, Element.portlet_mode));
      if (customPortletModeNav.next(Element.portal_managed)) {
        customPortletModeMD.setPortalManaged(customPortletModeNav.parseContent(ValueType.BOOLEAN));
      }
      md.addCustomPortletMode(customPortletModeMD);
    }

    //
    for (StaxNavigator<Element> customWindowStateNav : nav.fork(Element.custom_window_state)) {
      CustomWindowStateMetaData customWindowStateMD = new CustomWindowStateMetaData();
      customWindowStateMD.setId(customWindowStateNav.getAttribute("id"));
      customWindowStateMD.setDescription(
          readLocalizedString(customWindowStateNav, Element.description));
      customWindowStateMD.setWindowState(getContent(customWindowStateNav, Element.window_state));
      md.addCustomWindowState(customWindowStateMD);
    }

    //
    for (StaxNavigator<Element> userAttributeNav : nav.fork(Element.user_attribute)) {
      UserAttributeMetaData userAttributeMD = new UserAttributeMetaData();
      userAttributeMD.setId(userAttributeNav.getAttribute("id"));
      userAttributeMD.setDescription(readLocalizedString(userAttributeNav, Element.description));
      userAttributeMD.setName(getContent(userAttributeNav, Element.name));
      md.addUserAttribute(userAttributeMD);
    }

    //
    for (StaxNavigator<Element> securityConstraintNav : nav.fork(Element.security_constraint)) {
      SecurityConstraintMetaData securityConstraintMD = new SecurityConstraintMetaData();
      securityConstraintMD.setId(securityConstraintNav.getAttribute("id"));
      securityConstraintMD.setDisplayName(
          readLocalizedString(securityConstraintNav, Element.display_name));
      if (securityConstraintNav.next() != Element.portlet_collection) {
        throw new StaxNavException(
            nav.getLocation(),
            "Was expecting a portlet-collection element instead of "
                + securityConstraintNav.getName());
      }
      PortletCollectionMetaData portletCollectionMD = new PortletCollectionMetaData();
      while (securityConstraintNav.next(Element.portlet_name)) {
        portletCollectionMD.addPortletname(securityConstraintNav.getContent());
      }
      securityConstraintMD.setPortletList(portletCollectionMD);
      if (securityConstraintNav.next() != Element.user_data_constraint) {
        throw new StaxNavException(
            nav.getLocation(),
            "Was expecting a security-constraint element instead of "
                + securityConstraintNav.getName());
      }
      UserDataConstraintMetaData userDataConstraintMD = new UserDataConstraintMetaData();
      userDataConstraintMD.setDescription(
          readLocalizedString(securityConstraintNav, Element.description));
      if (securityConstraintNav.next() != Element.transport_guarantee) {
        throw new StaxNavException(
            nav.getLocation(),
            "Was expecting a transport-guarantee element instead of "
                + securityConstraintNav.getName());
      }
      userDataConstraintMD.setTransportGuarantee(
          securityConstraintNav.parseContent(TRANSPORT_GUARANTEE));
      securityConstraintMD.setUserDataConstraint(userDataConstraintMD);
      md.addSecurityConstraint(securityConstraintMD);
    }

    //
    if (nav.sibling(Element.resource_bundle)) {
      md.setResourceBundle(nav.getContent());
      nav.next();
    }

    //
    for (StaxNavigator<Element> filterNav : nav.fork(Element.filter)) {
      if (version < 2) {
        throw new DeploymentException("Cannot declare filter with " + PORTLET_1_0 + " descriptor");
      }
      FilterMetaData filterMD = new FilterMetaData();
      filterMD.setDescription(readLocalizedString(filterNav, Element.description));
      filterMD.setDisplayName(readLocalizedString(filterNav, Element.display_name));
      filterMD.setFilterName(getContent(filterNav, Element.filter_name));
      filterMD.setFilterClass(getContent(filterNav, Element.filter_class));
      while (filterNav.next(Element.lifecycle)) {
        filterMD.addLifecycle(filterNav.parseContent(LIFE_CYCLE));
      }
      for (InitParamMetaData initParamMD : readInitParams(filterNav)) {
        filterMD.addInitParam(initParamMD);
      }
      md.addFilter(filterMD);
    }

    //
    for (StaxNavigator<Element> filterMappingNav : nav.fork(Element.filter_mapping)) {
      if (version < 2) {
        throw new DeploymentException(
            "Cannot declare filter mapping with " + PORTLET_1_0 + " descriptor");
      }
      FilterMappingMetaData filterMappingMD = new FilterMappingMetaData();
      filterMappingMD.setName(getContent(filterMappingNav, Element.filter_name));
      while (filterMappingNav.next(Element.portlet_name)) {
        filterMappingMD.addPortletName(filterMappingNav.getContent());
      }
      md.addFilterMapping(filterMappingMD);
    }

    //
    if (nav.find(Element.default_namespace)) {
      String val = nav.getContent();
      try {
        md.setDefaultNamespace(new URI(val));
      } catch (URISyntaxException e) {
        throw new DeploymentException("Invalid URI " + val, e);
      }
      nav.next();
    }

    //
    for (StaxNavigator<Element> eventDefinitionNav : nav.fork(Element.event_definition)) {
      EventDefinitionMetaData eventDefinitionMD = new EventDefinitionMetaData();
      eventDefinitionMD.setId(eventDefinitionNav.getAttribute("id"));
      eventDefinitionMD.setDescription(
          readLocalizedString(eventDefinitionNav, Element.description));
      switch (eventDefinitionNav.next(NAME_OR_QNAME)) {
        case name:
          eventDefinitionMD.setName(eventDefinitionNav.getContent());
          break;
        case qname:
          eventDefinitionMD.setQname(readQName(eventDefinitionNav));
          break;
      }
      while (eventDefinitionNav.next(Element.alias)) {
        QName name = readQName(eventDefinitionNav);
        eventDefinitionMD.addAlias(name);
      }
      if (eventDefinitionNav.next(Element.value_type)) {
        eventDefinitionMD.setValueType(eventDefinitionNav.getContent());
      }
      md.addEventDefinition(eventDefinitionMD);
    }

    //
    for (StaxNavigator<Element> publicRenderParameterNav :
        nav.fork(Element.public_render_parameter)) {
      PublicRenderParameterMetaData publicRenderParameterMD = new PublicRenderParameterMetaData();
      publicRenderParameterMD.setId(publicRenderParameterNav.getAttribute("id"));
      publicRenderParameterMD.setDescription(
          readLocalizedString(publicRenderParameterNav, Element.description));
      publicRenderParameterMD.setIdentifier(
          getContent(publicRenderParameterNav, Element.identifier));
      switch (publicRenderParameterNav.next(NAME_OR_QNAME)) {
        case name:
          publicRenderParameterMD.setName(publicRenderParameterNav.getContent());
          break;
        case qname:
          publicRenderParameterMD.setQname(readQName(publicRenderParameterNav));
          break;
      }
      while (publicRenderParameterNav.next(Element.alias)) {
        QName name = readQName(publicRenderParameterNav);
        publicRenderParameterMD.addAlias(name);
      }
      md.addPublicRenderParameter(publicRenderParameterMD);
    }

    //
    for (StaxNavigator<Element> listenerNav : nav.fork(Element.listener)) {
      ListenerMetaData listenerMD = new ListenerMetaData();
      listenerMD.setId(listenerNav.getAttribute("id"));
      listenerMD.setDescription(readLocalizedString(listenerNav, Element.description));
      listenerMD.setDisplayName(readLocalizedString(listenerNav, Element.display_name));
      listenerMD.setListenerClass(getContent(listenerNav, Element.listener_class));
      md.addListener(listenerMD);
    }

    //
    for (StaxNavigator<Element> containerRuntimeNav : nav.fork(Element.container_runtime_option)) {
      ContainerRuntimeMetaData containerRuntimeOptionMD = new ContainerRuntimeMetaData();
      containerRuntimeOptionMD.setName(getContent(containerRuntimeNav, Element.name));
      while (containerRuntimeNav.next(Element.value)) {
        containerRuntimeOptionMD.addValue(containerRuntimeNav.getContent());
      }
      md.addContainerRuntime(containerRuntimeOptionMD);
    }

    //
    return md;
  }

  private LocalizedString readLocalizedString(StaxNavigator<Element> nav, Element element)
      throws DeploymentException {
    Map<Locale, String> descriptions = new LinkedHashMap<Locale, String>();
    while (nav.next(element)) {
      String lang = nav.getAttribute(XML_LANG);
      String description = nav.getContent();
      try {
        Locale locale = LocaleFormat.DEFAULT.getLocale(lang == null ? DEFAULT_LOCALE : lang);
        descriptions.put(locale, description);
      } catch (ConversionException e) {
        throw new DeploymentException("Invalid locale " + lang + "", e);
      }
    }
    if (descriptions.size() > 0) {
      return new LocalizedString(descriptions, new Locale(DEFAULT_LOCALE));
    } else {
      return null;
    }
  }

  private QName readQName(StaxNavigator<Element> nav) {
    String val = nav.getContent();
    int pos = val.indexOf(':');
    if (pos == -1) {
      return new QName(val);
    } else {
      String prefix = val.substring(0, pos);
      String localPart = val.substring(pos + 1);
      String uri = nav.getNamespaceByPrefix(prefix);
      if (uri == null) {
        throw new UnsupportedOperationException("todo");
      } else {
        return new QName(uri, localPart, prefix);
      }
    }
  }

  private Iterable<InitParamMetaData> readInitParams(StaxNavigator<Element> nav)
      throws DeploymentException {
    List<InitParamMetaData> list = Collections.emptyList();
    while (nav.next(Element.init_param)) {
      InitParamMetaData initParamMD = new InitParamMetaData();
      initParamMD.setId(nav.getAttribute("id"));
      initParamMD.setDescription(readLocalizedString(nav, Element.description));
      initParamMD.setName(getContent(nav, Element.name));
      initParamMD.setValue(getContent(nav, Element.value));
      if (list.isEmpty()) {
        list = new ArrayList<InitParamMetaData>();
      }
      list.add(initParamMD);
    }
    return list;
  }

  private String getContent(StaxNavigator<Element> nav, Element element) {
    if (nav.next(element)) {
      return nav.getContent();
    } else {
      throw new StaxNavException(
          nav.getLocation(), "Was expecting elemnt " + element + " to be present");
    }
  }
}
/** Represents a select element */
public class UIFormSelectBoxWithGroups extends UIFormStringInput {

  /** . */
  private static final Logger log = LoggerFactory.getLogger(UIFormSelectBoxWithGroups.class);

  /** It make SelectBox's ability to select multiple values */
  private boolean isMultiple_ = false;

  /** The size of the list (number of select options) */
  private int size_ = 1;

  /** The list of options */
  private List<SelectItem> options_;

  /** The javascript expression executed when an onChange event fires */
  private String onchange_;

  public UIFormSelectBoxWithGroups(
      String name, String bindingExpression, List<SelectItem> options) {
    super(name, bindingExpression, null);
    setOptions(options);
  }

  public final UIFormSelectBoxWithGroups setMultiple(boolean bl) {
    isMultiple_ = bl;
    return this;
  }

  public final UIFormSelectBoxWithGroups setSize(int i) {
    size_ = i;
    return this;
  }

  public UIFormSelectBoxWithGroups setValue(String value) {
    value_ = value;
    for (SelectItem option : options_) {
      if (option instanceof SelectOption) {
        if (((SelectOption) option).getValue().equals(value_))
          ((SelectOption) option).setSelected(true);
        else ((SelectOption) option).setSelected(false);
      } else if (option instanceof SelectOptionGroup) {
        ((SelectOptionGroup) option).setValue(value);
      }
    }

    return this;
  }

  public String[] getSelectedValues() {
    if (isMultiple_) {
      List<String> selectedValues = new ArrayList<String>();
      for (SelectItem option : options_) {
        if (option instanceof SelectOption) {
          if (((SelectOption) option).isSelected())
            selectedValues.add(((SelectOption) option).getValue());
        } else if (option instanceof SelectOptionGroup) {
          selectedValues.addAll(((SelectOptionGroup) option).getSelectedValues());
        }
      }
      return selectedValues.toArray(new String[0]);
    }
    return new String[] {value_};
  }

  public UIFormSelectBoxWithGroups setSelectedValues(String[] values) {
    for (SelectItem option : options_) {
      if (option instanceof SelectOption) {
        ((SelectOption) option).setSelected(false);
        for (String value : values) {
          if (value.equals(((SelectOption) option).getValue())) {
            ((SelectOption) option).setSelected(true);
            break;
          }
        }
      } else if (option instanceof SelectOptionGroup) {
        ((SelectOptionGroup) option).setSelectedValue(values);
      }
    }

    return this;
  }

  public final List<SelectItem> getOptions() {
    return options_;
  }

  public final UIFormSelectBoxWithGroups setOptions(List<SelectItem> options) {
    options_ = options;
    if (options_ == null || options_.size() < 1) return this;
    for (SelectItem option : options_) {
      if (option instanceof SelectOption) {
        value_ = ((SelectOption) option).getValue();
        break;
      }
    }
    return this;
  }

  public UIFormSelectBoxWithGroups addOptionGroup(String label, List<SelectOption> options) {
    SelectOptionGroup group = new SelectOptionGroup(label);
    group.setOptions(options);
    options_.add(group);
    return this;
  }

  @Override
  public void reset() {
    // TODO Auto-generated method stub - dang.tung
    if (options_ == null || options_.size() < 1) return;
    for (SelectItem option : options_) {
      if (option instanceof SelectOption) ((SelectOption) option).setSelected(false);
      else if (option instanceof SelectOptionGroup) {
        ((SelectOptionGroup) option).reset();
      }
    }
    for (SelectItem option : options_) {
      if (option instanceof SelectOption) {
        value_ = ((SelectOption) option).getValue();
        ((SelectOption) option).setSelected(true);
        break;
      }
    }
  }

  public void setOnChange(String onchange) {
    onchange_ = onchange;
  }

  @SuppressWarnings("deprecation")
  public UIFormSelectBoxWithGroups setDisabled(boolean disabled) {
    return (UIFormSelectBoxWithGroups) super.setDisabled(disabled);
  }

  @SuppressWarnings("unused")
  public void decode(Object input, WebuiRequestContext context) throws Exception {
    String[] values = context.getRequestParameterValues(getId());
    if (values == null) {
      value_ = null;
      for (SelectItem option : options_) {
        if (option instanceof SelectOption) ((SelectOption) option).setSelected(false);
        else if (option instanceof SelectOptionGroup) {
          for (SelectOption opt : ((SelectOptionGroup) option).getOptions()) {
            opt.setSelected(false);
          }
        }
      }
      return;
    }

    int i = 0;
    value_ = values[0];
    for (SelectItem item : options_) {
      if (item instanceof SelectOption) {
        if (i > -1 && ((SelectOption) item).getValue().equals(values[i])) {
          ((SelectOption) item).setSelected(true);
          if (values.length == ++i) i = -1;
        } else ((SelectOption) item).setSelected(false);
      } else if (item instanceof SelectOptionGroup) {
        for (SelectOption opt : ((SelectOptionGroup) item).getOptions()) {
          if (i > -1 && ((SelectOption) opt).getValue().equals(values[i])) {
            ((SelectOption) opt).setSelected(true);
            if (values.length == ++i) i = -1;
          } else {
            ((SelectOption) opt).setSelected(false);
          }
        }
      }
    }
  }

  //  protected String renderOnChangeAction(UIForm uiform) throws Exception {
  //    StringBuilder builder = new StringBuilder();
  //    builder.append(" onchange=\"javascript:eXo.webui.UIForm.submitForm('").
  //            append("").append("','").append(onchange_).append("');\" ");
  //    return builder.toString();
  //  }

  protected String renderOnChangeEvent(UIForm uiForm) throws Exception {
    return uiForm.event(onchange_, (String) null);
  }

  protected UIForm getFrom() {
    return getAncestorOfType(UIForm.class);
  }

  public void processRender(WebuiRequestContext context) throws Exception {
    ResourceBundle res = context.getApplicationResourceBundle();
    UIForm uiForm = getAncestorOfType(UIForm.class);
    String formId = null;
    if (uiForm.getId().equals("UISearchForm")) formId = uiForm.<UIComponent>getParent().getId();
    else formId = uiForm.getId();

    Writer w = context.getWriter();
    w.write("<select class=\"selectbox\" name=\"");
    w.write(name);
    w.write("\"");
    if (onchange_ != null) {
      w.append(" onchange=\"").append(renderOnChangeEvent(uiForm)).append("\"");
    }

    if (isMultiple_) w.write(" multiple=\"true\"");
    if (size_ > 1) w.write(" size=\"" + size_ + "\"");

    if (isDisabled()) w.write(" disabled ");

    renderHTMLAttributes(w);

    w.write(">\n");

    for (SelectItem item : options_) {
      String label = item.getLabel();
      if (item instanceof SelectOption) {
        try {
          label = res.getString(formId + ".label.option." + ((SelectOption) item).getValue());
        } catch (MissingResourceException ex) {
        }

        w.write(renderOption(((SelectOption) item), label));

      } else if (item instanceof SelectOptionGroup) {
        label = item.getLabel();
        try {
          label = res.getString(getFrom().getId() + ".optionGroup.label." + label);
        } catch (MissingResourceException ex) {
          log.debug("Could not find: " + getFrom().getId() + ".optionGroup.label." + label);
        }
        w.write("<optgroup label=\"");
        w.write(label);
        w.write("\">\n");
        for (SelectOption opt : ((SelectOptionGroup) item).getOptions()) {
          label = opt.getLabel();
          try {
            label = res.getString(formId + ".label.option." + opt.getValue());
          } catch (MissingResourceException ex) {
          }
          w.write(renderOption(opt, label));
        }
        w.write("</optgroup>\n");
      }
    }
    w.write("</select>\n");
    if (this.isMandatory()) w.write(" *");
  }

  private String renderOption(SelectOption option, String label) {
    StringBuffer buf = new StringBuffer();
    buf.append("<option value=\"");
    buf.append(option.getValue());
    buf.append("\"");
    if (option.isSelected()) buf.append("selected=\"selected\"");
    buf.append(">");
    buf.append(label);
    buf.append("</option>\n");
    return buf.toString();
  }
}