Package ca.carleton.gcrc.couch.user

Source Code of ca.carleton.gcrc.couch.user.UserServlet

package ca.carleton.gcrc.couch.user;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Vector;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ca.carleton.gcrc.couch.client.CouchDb;
import ca.carleton.gcrc.couch.client.CouchDbSecurityDocument;
import ca.carleton.gcrc.couch.client.CouchDesignDocument;
import ca.carleton.gcrc.couch.client.CouchUserDb;
import ca.carleton.gcrc.couch.user.agreement.AgreementRobot;
import ca.carleton.gcrc.couch.user.agreement.AgreementRobotSettings;
import ca.carleton.gcrc.couch.user.db.UserRepository;
import ca.carleton.gcrc.couch.user.db.UserRepositoryCouchDb;
import ca.carleton.gcrc.couch.user.error.TokenExpiredException;
import ca.carleton.gcrc.couch.user.error.UserUpdatedException;
import ca.carleton.gcrc.couch.user.mail.PasswordRecoveryGenerator;
import ca.carleton.gcrc.couch.user.mail.PasswordReminderGenerator;
import ca.carleton.gcrc.couch.user.mail.UserCreationGenerator;
import ca.carleton.gcrc.couch.user.mail.UserMailNotificationImpl;
import ca.carleton.gcrc.couch.utils.CouchDbTemplateMailMessageGenerator;
import ca.carleton.gcrc.mail.MailDelivery;
import ca.carleton.gcrc.mail.messageGenerator.MailMessageGenerator;

@SuppressWarnings("serial")
public class UserServlet extends HttpServlet {

  public static final String ConfigAttributeName_AtlasName = "UserServlet_AtlasName";
  public static final String ConfigAttributeName_UserDb = "UserServlet_UserDb";
  public static final String ConfigAttributeName_DocumentDb = "UserServlet_DocumentDb";
  public static final String ConfigAttributeName_ServerKey = "UserServlet_ServerKey";
 
  final protected Logger logger = LoggerFactory.getLogger(this.getClass());

  private String atlasName = null;
  private CouchUserDb userDb = null;
  private CouchDb documentDb = null;
  private byte[] serverKey = null;
  private UserServletActions actions = null;
  private AgreementRobot agreementRobot = null;
 
  public UserServlet(){
   
  }
 
  public void init(ServletConfig config) throws ServletException {
    ServletContext context = config.getServletContext();
   
    logger.info(this.getClass().getSimpleName()+" servlet initialization - start");
   
    // AtlasName
    {
      Object obj = context.getAttribute(ConfigAttributeName_AtlasName);
      if( null == obj ){
        throw new ServletException("Atlas name is not specified ("+ConfigAttributeName_AtlasName+")");
      }
      if( obj instanceof String ){
        atlasName = (String)obj;
      } else {
        throw new ServletException("Unexpected object for atlas name: "+obj.getClass().getName());
      }
    }
   
    // UserDb
    {
      Object obj = context.getAttribute(ConfigAttributeName_UserDb);
      if( null == obj ){
        throw new ServletException("User database is not specified ("+ConfigAttributeName_UserDb+")");
      }
      if( obj instanceof CouchUserDb ){
        userDb = (CouchUserDb)obj;
      } else {
        throw new ServletException("Unexpected object for user database: "+obj.getClass().getName());
      }
    }
   
    // DocumentDb
    {
      Object obj = context.getAttribute(ConfigAttributeName_DocumentDb);
      if( null == obj ){
        throw new ServletException("Document database is not specified ("+ConfigAttributeName_DocumentDb+")");
      }
      if( obj instanceof CouchDb ){
        documentDb = (CouchDb)obj;
      } else {
        throw new ServletException("Unexpected object for document database: "+obj.getClass().getName());
      }
    }
   
    // Mail Delivery
    UserMailNotificationImpl userMailNotification = null;
    {
      Object obj = context.getAttribute(MailDelivery.ConfigAttributeName_MailDelivery);
      if( null == obj ){
        throw new ServletException("Mail delivery is not specified ("+MailDelivery.ConfigAttributeName_MailDelivery+")");
      }
      if( obj instanceof MailDelivery ){
        MailDelivery mailDelivery = (MailDelivery)obj;
        userMailNotification = new UserMailNotificationImpl(mailDelivery);
      } else {
        throw new ServletException("Unexpected object for mail delivery: "+obj.getClass().getName());
      }
     
      // Load e-mail templates
      {
        MailMessageGenerator template = new UserCreationGenerator();
        CouchDbTemplateMailMessageGenerator couchTemplate = new CouchDbTemplateMailMessageGenerator(
            documentDb,
            "org.nunaliit.email_template.user_creation",
            template
            );
        userMailNotification.setUserCreationGenerator(couchTemplate);
      }
      {
        MailMessageGenerator template = new PasswordRecoveryGenerator();
        CouchDbTemplateMailMessageGenerator couchTemplate = new CouchDbTemplateMailMessageGenerator(
            documentDb,
            "org.nunaliit.email_template.password_recovery",
            template
            );
        userMailNotification.setPasswordRecoveryGenerator(couchTemplate);
      }
      {
        MailMessageGenerator template = new PasswordReminderGenerator();
        CouchDbTemplateMailMessageGenerator couchTemplate = new CouchDbTemplateMailMessageGenerator(
            documentDb,
            "org.nunaliit.email_template.password_reminder",
            template
            );
        userMailNotification.setPasswordReminderGenerator(couchTemplate);
      }
    }
   
    // Server Key
    {
      Object obj = context.getAttribute(ConfigAttributeName_ServerKey);
      if( null != obj ){
        if( obj instanceof ByteBuffer ){
          ByteBuffer serverKeyBuffer = (ByteBuffer)obj;
          serverKey = serverKeyBuffer.array();
        } else {
          throw new ServletException("Unexpected object for server key: "+obj.getClass().getName());
        }
      }
    }
   
    // Nunaliit user design document
    CouchDesignDocument userDesignDocument = null;
    if( null != userDb ){
      try {
        userDesignDocument = userDb.getDesignDocument("nunaliit_user");
      } catch (Exception e) {
        throw new ServletException("Unable to create user design document.",e);
      }
    }
   
    UserRepository userRepository = new UserRepositoryCouchDb(userDb, userDesignDocument);
   
    actions = new UserServletActions(atlasName, documentDb, userRepository, userMailNotification);
    if( null != serverKey ){
      actions.setServerKey(serverKey);
    }
   
    // Add atlas role to access user database
    try {
      CouchDbSecurityDocument securityDoc = userDb.getSecurityDocument();
      Collection<String> adminRoles = securityDoc.getAdminRoles();
     
      boolean updateRequired = false;

      // <atlas>_administrator
      {
        String targetRole = atlasName + "_administrator";
        if( false == adminRoles.contains(targetRole) ) {
          securityDoc.addAdminRole(targetRole);
          updateRequired = true;
        }
      }

      // administrator
      {
        String targetRole = "administrator";
        if( false == adminRoles.contains(targetRole) ) {
          securityDoc.addAdminRole(targetRole);
          updateRequired = true;
        }
      }

      if( updateRequired ) {
        userDb.setSecurityDocument(securityDoc);
      }
    } catch(Exception e) {
      throw new ServletException("Error while updating security document on _users database",e);
    }
   
    // Start agreement robot
    try {
      AgreementRobotSettings settings = new AgreementRobotSettings();
      settings.setAtlasName(atlasName);
      settings.setDocumentDesignDocument(documentDb.getDesignDocument("atlas"));
      settings.setUserDb(userDb);
     
      agreementRobot = new AgreementRobot(settings);
     
      agreementRobot.start();
       
    } catch (Exception e) {
      logger.error("Error starting agreement worker",e);
      throw new ServletException("Error starting agreement worker",e);
    }
   

    logger.info(this.getClass().getSimpleName()+" servlet initialization - completed");
  }

  public void destroy() {
    try {
      if( agreementRobot != null ) {
        agreementRobot.stopTimeoutMillis(5*1000); // 5 seconds
      }
    } catch (Exception e) {
      logger.error("Unable to shutdown agreement worker", e);
    }
   
  }

  @Override
  protected void doGet(
    HttpServletRequest req
    ,HttpServletResponse resp
    ) throws ServletException, IOException {
   
    try {
      List<String> path = computeRequestPath(req);
     
      if( path.size() < 1 ) {
        JSONObject result = actions.getWelcome();
        sendJsonResponse(resp, result);

      } else if( path.size() == 2 && path.get(0).equals("getUser") ) {
          JSONObject result = actions.getUser(path.get(1));
          sendJsonResponse(resp, result);

      } else if( path.size() == 1 && path.get(0).equals("getUser") ) {
        String[] userStrings = req.getParameterValues("user");
        String[] emailStrings = req.getParameterValues("email");
       
        // Request by user name
        if( null != userStrings && userStrings.length > 0 ){
          String userName = userStrings[0];
          JSONObject result = actions.getUser(userName);
          sendJsonResponse(resp, result);
         
        } else if( null != emailStrings && emailStrings.length > 0 ){
          // Request by e-mail
          String emailAddress = emailStrings[0];
          JSONObject result = actions.getUserFromEmailAddress(emailAddress);
          sendJsonResponse(resp, result);
        }

      } else if( path.size() == 1 && path.get(0).equals("getUsers") ) {
        String[] userStrings = req.getParameterValues("user");
       
        List<String> users = new ArrayList<String>(userStrings.length);
        for(String userString : userStrings){
          users.add(userString);
        }
       
        JSONObject result = actions.getUsers(users);
        sendJsonResponse(resp, result);

      } else if( path.size() == 1 && path.get(0).equals("getUserDocument") ) {
        String[] userStrings = req.getParameterValues("user");
        if( null == userStrings ||  userStrings.length != 1 ){
          throw new Exception("Parameter 'user' must be specified exactly once");
        }
       
        String userId = userStrings[0];

        Cookie[] cookies = req.getCookies();

        ArrayList<String> userIds = new ArrayList<String>(1);
        userIds.add(userId);
       
        Collection<JSONObject> result = actions.getUserDocuments(userIds, cookies);
       
        if( result.size() < 1 ){
          throw new Exception("User document not found (name="+userId+")");
        }
       
        sendJsonResponse(resp, result.iterator().next());

      } else if( path.size() == 1 && path.get(0).equals("getUserDocuments") ) {
        String[] userStrings = req.getParameterValues("user");
        if( null == userStrings ||  userStrings.length < 1 ){
          throw new Exception("Parameter 'user' must be specified at least once");
        }
       
        List<String> userIds = new ArrayList<String>(userStrings.length);
        for(String userString : userStrings){
          userIds.add(userString);
        }

        Cookie[] cookies = req.getCookies();

        Collection<JSONObject> userDocs = actions.getUserDocuments(userIds, cookies);
       
        JSONObject result = new JSONObject();
       
        JSONArray jsonArr = new JSONArray();
        result.put("users", jsonArr);
       
        for(JSONObject userDoc : userDocs){
          jsonArr.put(userDoc);
        }
       
        sendJsonResponse(resp, result);

      } else if( path.size() == 1 && path.get(0).equals("initUserCreation") ) {
        String[] emailStrings = req.getParameterValues("email");

        if( null == emailStrings || emailStrings.length < 1 ){
          throw new Exception("'email' parameter must be specified");
        }
        if( emailStrings.length > 1 ){
          throw new Exception("'email' parameter must be specified exactly once");
        }
       
        JSONObject result = actions.initUserCreation(emailStrings[0]);
        sendJsonResponse(resp, result);

      } else if( path.size() == 1 && path.get(0).equals("validateUserCreation") ) {
        String[] tokenStrings = req.getParameterValues("token");

        if( null == tokenStrings || tokenStrings.length < 1 ){
          throw new Exception("'token' parameter must be specified");
        }
        if( tokenStrings.length > 1 ){
          throw new Exception("'token' parameter must be specified exactly once");
        }
       
        JSONObject result = actions.validateUserCreation(tokenStrings[0]);
        sendJsonResponse(resp, result);

      } else if( path.size() == 1 && path.get(0).equals("initPasswordRecovery") ) {
        String[] emailStrings = req.getParameterValues("email");

        if( null == emailStrings || emailStrings.length < 1 ){
          throw new Exception("'email' parameter must be specified");
        }
        if( emailStrings.length > 1 ){
          throw new Exception("'email' parameter must be specified exactly once");
        }
       
        JSONObject result = actions.initPasswordRecovery(emailStrings[0]);
        sendJsonResponse(resp, result);

      } else if( path.size() == 1 && path.get(0).equals("validatePasswordRecovery") ) {
        String[] tokenStrings = req.getParameterValues("token");

        if( null == tokenStrings || tokenStrings.length < 1 ){
          throw new Exception("'token' parameter must be specified");
        }
        if( tokenStrings.length > 1 ){
          throw new Exception("'token' parameter must be specified exactly once");
        }
       
        JSONObject result = actions.validatePasswordRecovery(tokenStrings[0]);
        sendJsonResponse(resp, result);

      } else if( path.size() == 1 && path.get(0).equals("completePasswordRecovery") ) {

        // Token
        String token = null;
        {
          String[] tokenStrings = req.getParameterValues("token");
          if( null == tokenStrings || tokenStrings.length < 1 ){
            throw new Exception("'token' parameter must be specified");
          }
          if( tokenStrings.length > 1 ){
            throw new Exception("'token' parameter must be specified exactly once");
          }
          token = tokenStrings[0];
        }

        // Password
        String password = null;
        {
          String[] passwordStrings = req.getParameterValues("password");
          if( null == passwordStrings || passwordStrings.length < 1 ){
            throw new Exception("'password' parameter must be specified");
          }
          if( passwordStrings.length > 1 ){
            throw new Exception("'password' parameter must be specified exactly once");
          }
          password = passwordStrings[0];
        }
       
        // Email Password
        boolean emailPassword = false;
        {
          String[] emailPasswordStrings = req.getParameterValues("emailPassword");
          if( null != emailPasswordStrings ) {
            if( emailPasswordStrings.length > 1 ){
              throw new Exception("'emailPassword' parameter must not be specified more than once");
            }
            emailPassword = Boolean.parseBoolean( emailPasswordStrings[0] );
          }
        }
       
        JSONObject result = actions.completePasswordRecovery(token,password,emailPassword);
        sendJsonResponse(resp, result);

      } else if( path.size() == 1 && path.get(0).equals("generatePassword") ) {
        JSONObject result = actions.generatePassword();
        sendJsonResponse(resp, result);

      } else {
        throw new Exception("Invalid action requested");
      }
     
    } catch(Exception e) {
      reportError(e, resp);
    }
  }
 
  @Override
  protected void doPost(
    HttpServletRequest req
    ,HttpServletResponse resp
    ) throws ServletException, IOException {

    try {
      List<String> path = computeRequestPath(req);
     
      if( path.size() == 1 && path.get(0).equals("completeUserCreation") ) {

        // Token
        String token = null;
        {
          String[] tokenStrings = req.getParameterValues("token");
          if( null == tokenStrings || tokenStrings.length < 1 ){
            throw new Exception("'token' parameter must be specified");
          }
          if( tokenStrings.length > 1 ){
            throw new Exception("'token' parameter must be specified exactly once");
          }
          token = tokenStrings[0];
        }

        // Display Name
        String displayName = null;
        {
          String[] displayStrings = req.getParameterValues("display");
          if( null == displayStrings || displayStrings.length < 1 ){
            throw new Exception("'display' parameter must be specified");
          }
          if( displayStrings.length > 1 ){
            throw new Exception("'display' parameter must be specified exactly once");
          }
          displayName = displayStrings[0];
        }

        // Password
        String password = null;
        {
          String[] passwordStrings = req.getParameterValues("password");
          if( null == passwordStrings || passwordStrings.length < 1 ){
            throw new Exception("'password' parameter must be specified");
          }
          if( passwordStrings.length > 1 ){
            throw new Exception("'password' parameter must be specified exactly once");
          }
          password = passwordStrings[0];
        }
       
        // Email Password
        boolean emailPassword = false;
        {
          String[] emailPasswordStrings = req.getParameterValues("emailPassword");
          if( null != emailPasswordStrings ) {
            if( emailPasswordStrings.length > 1 ){
              throw new Exception("'emailPassword' parameter must not be specified more than once");
            }
            emailPassword = Boolean.parseBoolean( emailPasswordStrings[0] );
          }
        }
       
        // User Agreement
        String userAgreement = null;
        {
          String[] userAgreements = req.getParameterValues("userAgreement");
          if( null != userAgreements ) {
            if( userAgreements.length > 1 ){
              throw new Exception("'userAgreement' parameter must not be specified more than once");
            }
            if( userAgreements.length == 1 ){
              userAgreement = userAgreements[0];
            }
          }
        }
        if( "".equals(userAgreement) ){
          userAgreement = null;
        }
       
        JSONObject result = actions.completeUserCreation(
            token
            ,displayName
            ,password
            ,emailPassword
            ,userAgreement
            );
        sendJsonResponse(resp, result);

      } else if( path.size() == 1 && path.get(0).equals("acceptUserAgreement") ) {

        // User Agreement
        String userAgreement = null;
        {
          String[] userAgreements = req.getParameterValues("userAgreement");
          if( null != userAgreements ) {
            if( userAgreements.length > 1 ){
              throw new Exception("'userAgreement' parameter must not be specified more than once");
            }
            if( userAgreements.length == 1 ){
              userAgreement = userAgreements[0];
            }
          }
        }
        if( "".equals(userAgreement) ){
          userAgreement = null;
        }

        Cookie[] cookies = req.getCookies();
       
        JSONObject result = actions.acceptUserAgreement(cookies, userAgreement);
        sendJsonResponse(resp, result);

      } else {
        throw new Exception("Invalid action requested");
      }
     
    } catch(Exception e) {
      reportError(e, resp);
    }
  }
 
  private void sendJsonResponse(HttpServletResponse resp, JSONObject result) throws Exception {
    if( null == result ) {
      resp.setStatus(304); // not modified
    } else {
      resp.setStatus(200);
    }
    resp.setContentType("application/json");
    resp.setCharacterEncoding("utf-8");
    resp.addHeader("Cache-Control", "no-cache");
    resp.addHeader("Pragma", "no-cache");
    resp.addHeader("Expires", "-1");
   
    if( null != result ) {
      OutputStreamWriter osw = new OutputStreamWriter(resp.getOutputStream(), "UTF-8");
      result.write(osw);
      osw.flush();
    }
   
  }

  private void reportError(Throwable t, HttpServletResponse resp) throws ServletException {
    try {
      resp.setStatus(400);
      resp.setContentType("application/json");
      resp.setCharacterEncoding("utf-8");
      resp.addHeader("Cache-Control", "must-revalidate");
     
      JSONObject errorObj = new JSONObject();
      errorObj.put("error", t.getMessage());
     
      int limit = 15;
      Throwable cause = t;
      while( null != cause && limit > 0 ){
        if( cause instanceof TokenExpiredException ){
          errorObj.put("tokenExpired", true);
        }
        if( cause instanceof UserUpdatedException ){
          errorObj.put("userUpdated", true);
        }
       
        --limit;
        cause = cause.getCause();
      }
     
      OutputStreamWriter osw = new OutputStreamWriter(resp.getOutputStream(), "UTF-8");
      errorObj.write(osw);
      osw.flush();
     
    } catch (Exception e) {
      logger.error("Unable to report error", e);
      throw new ServletException("Unable to report error", e);
    }
  }
 
  private List<String> computeRequestPath(HttpServletRequest req) throws Exception {
    List<String> paths = new Vector<String>();
   
    String path = req.getPathInfo();
    if( null != path ) {
      boolean first = true;
      String[] pathFragments = path.split("/");
      for(String f : pathFragments) {
        if( first ){
          // Skip first which is empty (/getUser/user1 -> "","getUser","user1")
          first = false;
        } else {
          paths.add(f);
        }
      }
    }
   
    return paths;
  }
}
TOP

Related Classes of ca.carleton.gcrc.couch.user.UserServlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.