public class PasswordManagerServiceImpl implements PortletServiceProvider, PasswordManagerService {

  private static PortletLog _log = SportletLog.getInstance(PasswordManagerServiceImpl.class);
  private static PersistenceManagerRdbms pm = null;
  private String userPasswordImpl = PasswordImpl.class.getName();

  public PasswordManagerServiceImpl() {}

  public void init(PortletServiceConfig config) {
    pm = PersistenceManagerFactory.createGridSphereRdbms();
  }

  public void destroy() {}

  public Password getPassword(User user) {
    return getPasswordImpl(user);
  }

  /**
   * This method returns the <code>PasswordImpl</code> associated with a user and is called
   * internally by other methods in this class.
   */
  private PasswordImpl getPasswordImpl(User user) {
    PasswordImpl password = null;
    String query =
        "select pw from "
            + this.userPasswordImpl
            + " pw where pw.sportletUser.oid='"
            + user.getID()
            + "'";
    try {
      password = (PasswordImpl) pm.restore(query);
    } catch (PersistenceManagerException e) {
      _log.error("Unable to retrieve password for user", e);
    }
    return password;
  }

  public void validateSuppliedPassword(User user, String value) throws InvalidPasswordException {
    PasswordImpl password = getPasswordImpl(user);
    if (password == null) {
      _log.debug("No password found for user");
      throw new InvalidPasswordException("No password found for user!");
    }
    // _log.debug("Stored value is " + password.getValue());
    // _log.debug("Provided value is " + value);

    // MD5 hash of password value
    try {
      MessageDigest md5 = MessageDigest.getInstance("MD5");
      md5.update(value.getBytes());
      value = toHex(md5.digest());

      // _log.debug("Hash of value is " + value);
      if (!password.getValue().equals(value)) {
        throw new InvalidPasswordException("Supplied password does not match user password!");
      }
    } catch (NoSuchAlgorithmException e) {
      _log.error("No such algorithm: MD5", e);
    }
  }

  public void savePassword(Password editor) {
    try {
      if (editor instanceof PasswordImpl) {
        PasswordImpl pass = (PasswordImpl) editor;
        try {
          MessageDigest md5 = MessageDigest.getInstance("MD5");
          md5.update(pass.getValue().getBytes());
          String value = toHex(md5.digest());
          pass.setValue(value);
        } catch (NoSuchAlgorithmException e) {
          throw new PersistenceManagerException("Can't get MD5 algorithm! " + e.getMessage());
        }
        pm.saveOrUpdate(pass);
      }
    } catch (PersistenceManagerException e) {
      _log.error("Unable to create or update password for user", e);
    }
  }

  public String getHashedPassword(String pass) {
    try {
      MessageDigest md5 = MessageDigest.getInstance("MD5");
      md5.update(pass.getBytes());
      return toHex(md5.digest());
    } catch (NoSuchAlgorithmException e) {
      _log.error("NoSuchAlgorithm MD5!", e);
    }
    return null;
  }

  public void saveHashedPassword(Password editor) {
    try {
      if (editor instanceof PasswordImpl) {
        PasswordImpl pass = (PasswordImpl) editor;
        pm.saveOrUpdate(pass);
      }
    } catch (PersistenceManagerException e) {
      _log.error("Unable to create or update password for user", e);
    }
  }

  public void deletePassword(User user) {
    Password password = getPassword(user);
    if (password != null) {
      deletePassword(password);
    }
  }

  private void deletePassword(Password password) {
    try {
      pm.delete(password);
    } catch (PersistenceManagerException e) {
      _log.error("Unable to delete password", e);
    }
  }

  public boolean hasPassword(User user) {
    Password password = getPassword(user);
    return (password != null);
  }

  public PasswordEditor editPassword(User user) {
    PasswordImpl password = this.getPasswordImpl(user);
    if (password == null) {
      password = new PasswordImpl();
      password.setUser(user);
      password.setDateCreated(Calendar.getInstance().getTime());
      this.savePassword(password);
    }
    return password;
  }

  /**
   * Return an 8 byte representation of the 32 byte MD5 digest
   *
   * @param digest the message digest
   * @return String 8 byte hexadecimal
   */
  private static String toHex(byte[] digest) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < digest.length; i++) {
      buf.append(Integer.toHexString((int) digest[i] & 0x00FF));
    }
    return buf.toString();
  }
}
/**
 * The <code>PortletWebApplicationImpl</code> is an implementation of a <code>PortletWebApplication
 * </code> that represents a collection of portlets contained in a packaged WAR file. Currently
 * under development is the notion of dynamically managing portlet web applications.
 */
public class PortletWebApplicationImpl extends BasePortletWebApplicationImpl
    implements PortletWebApplication {

  private PortletLog log = SportletLog.getInstance(PortletWebApplicationImpl.class);
  private PortletDeploymentDescriptor pdd = null;

  /**
   * Constructs an instance of a PortletWebApplicationImpl from a supplied ui application name and
   * corresponding <code>ServletContext</code>
   *
   * @param webApplicationName the the web application name
   * @param context the <code>ServletContext</code>
   */
  public PortletWebApplicationImpl(String webApplicationName, ServletContext context)
      throws PortletException {
    super(context);
    this.webApplicationName = webApplicationName;
    // get the servlet context for the coreportlets webapp
    String contextURIPath;
    if (webApplicationName.startsWith("/")) {
      contextURIPath = webApplicationName;
      this.webApplicationName = webApplicationName.substring(1);
    } else {
      contextURIPath = "/" + webApplicationName;
    }

    // Get the cross context servlet context
    ServletContext ctx = context.getContext(contextURIPath);
    // System.err.println("contextURIPath: " + contextURIPath);
    // System.err.println("contextName: " + ctx.getServletContextName());
    // System.err.println("context path: " + ctx.getRealPath(""));

    // System.err.println("testing example portlets");
    // ServletContext testsc = context.getContext("/exampleportlets");
    // System.err.println("description: " + ctx.getServletContextName());
    // System.err.println("testing core portlets");
    // testsc = context.getContext("/coreportlets");
    // System.err.println("description: " + testsc.getServletContextName());
    // System.err.println("context path: " + te.getRealPath(""));

    if (ctx == null) {
      log.error(webApplicationName + ": Unable to get ServletContext for: " + contextURIPath);
      throw new PortletException(
          webApplicationName + ": Unable to get ServletContext for: " + contextURIPath);
    }
    log.debug("context path: " + ctx.getRealPath(""));
    this.webAppDescription = ctx.getServletContextName();

    // load portlet.xml
    loadPortlets(ctx, Thread.currentThread().getContextClassLoader());
    // load services xml
    if (!isJSR) loadServices(ctx, Thread.currentThread().getContextClassLoader());
    // load roles.xml
    if (!isJSR) loadRoles(ctx);
    // load group.xml (and if found load layout.xml)
    if (!isJSR) loadGroup(ctx);
  }

  /**
   * Loads collection of portlets from portlet descriptor file using the associated <code>
   * ServletContext</code>
   *
   * @param ctx the <code>ServletContext</code>
   */
  protected void loadPortlets(ServletContext ctx, ClassLoader loader) throws PortletException {

    // First we see if this is a gridsphere portlet descriptor and load in as gridsphere-portlet.xml
    log.info("Loading gridsphere-portlet.xml...");
    String gsportletXMLfile = ctx.getRealPath("/WEB-INF/gridsphere-portlet.xml");
    File gs = new File(gsportletXMLfile);

    String portletXMLfile = ctx.getRealPath("/WEB-INF/portlet.xml");
    File jsr = new File(portletXMLfile);

    if (gs.exists() && jsr.exists()) {
      isJSR = true;
    }

    if (!gs.exists()) {
      // trying
      log.info("Instead loading portlet.xml as a gridsphere portlet descriptor...");
      gsportletXMLfile = portletXMLfile;
    }
    // String portletMappingFile =
    // GridSphereConfig.getProperty(GridSphereConfigProperties.PORTLET_MAPPING);

    String portletMappingFile =
        GridSphereConfig.getServletContext().getRealPath("/WEB-INF/mapping/portlet-mapping.xml");
    pdd = null;
    try {
      pdd = new PortletDeploymentDescriptor(gsportletXMLfile, portletMappingFile);
    } catch (Exception e) {
      log.error("Mapping Error! " + webApplicationName, e);
      throw new PortletException(
          "Unable to load portlets from: " + webApplicationName + " + due to mapping error!");
    }
    // Every SportletDefinition has a PortletApplication and possibly multiple
    // ConcretePortletConfig's
    Iterator portletDefs = pdd.getPortletDefinitionList().iterator();

    // Iterate thru portlet definitions for portlet applications
    while (portletDefs.hasNext()) {
      SportletDefinition portletDef = (SportletDefinition) portletDefs.next();
      ApplicationPortlet portletApp =
          new ApplicationPortletImpl(pdd, portletDef, webApplicationName, ctx);
      String portletAppID = portletApp.getApplicationPortletID();
      appPortlets.put(portletAppID, portletApp);
    }
  }

  public void init() {}

  /**
   * Under development. A portlet web application can unregister itself from the application server
   */
  public void destroy() {
    // log.debug("removing application tab :" + webApplicationName);
    // PortletTabRegistry.removeGroupTab(webApplicationName);
    PersistenceManagerFactory.destroyPersistenceManagerRdbms(webApplicationName);
    SportletServiceFactory.shutdownServices(webApplicationName);
    appPortlets = null;
  }

  /**
   * Returns the portlet web application name
   *
   * @return the ui application name
   */
  public String getWebApplicationName() {
    return webApplicationName;
  }

  /**
   * Returns the portlet web application description
   *
   * @return the portlet web application description
   */
  public String getWebApplicationDescription() {
    return webAppDescription;
  }

  /**
   * Returns the collection of application portlets contained by this portlet web application
   *
   * @return the collection of application portlets
   */
  public Collection getAllApplicationPortlets() {
    return ((appPortlets != null ? appPortlets.values() : new ArrayList()));
  }
}