Package ca.carleton.gcrc.couch.config

Source Code of ca.carleton.gcrc.couch.config.ConfigServlet

package ca.carleton.gcrc.couch.config;

import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

import org.apache.log4j.Logger;

import ca.carleton.gcrc.couch.app.DesignDocumentPush;
import ca.carleton.gcrc.couch.app.DocumentInitialize;
import ca.carleton.gcrc.couch.app.DocumentPush;
import ca.carleton.gcrc.couch.client.CouchClient;
import ca.carleton.gcrc.couch.client.CouchDb;
import ca.carleton.gcrc.couch.client.CouchDesignDocument;
import ca.carleton.gcrc.couch.client.CouchFactory;
import ca.carleton.gcrc.couch.config.listener.ConfigListener;
import ca.carleton.gcrc.couch.config.listener.ConfigListenerCollection;
import ca.carleton.gcrc.couch.config.listener.ConfigWorker;
import ca.carleton.gcrc.couch.config.listener.CouchConfig;
import ca.carleton.gcrc.couch.config.listener.CouchConfigFactory;
import ca.carleton.gcrc.couch.onUpload.UploadListener;
import ca.carleton.gcrc.couch.onUpload.UploadWorker;
import ca.carleton.gcrc.couch.onUpload.UploadWorkerSettings;
import ca.carleton.gcrc.couch.onUpload.gpx.GpxFileConverter;
import ca.carleton.gcrc.couch.onUpload.mail.MailNotification;
import ca.carleton.gcrc.couch.onUpload.mail.MailNotificationImpl;
import ca.carleton.gcrc.couch.onUpload.mail.MailNotificationNull;
import ca.carleton.gcrc.couch.onUpload.multimedia.MultimediaFileConverter;
import ca.carleton.gcrc.nunaliit2.couch.replication.ReplicationWorker;
import ca.carleton.gcrc.olkit.multimedia.utils.MultimediaConfiguration;
import ca.carleton.gcrc.upload.OnUploadedListenerSingleton;
import ca.carleton.gcrc.upload.UploadServlet;
import ca.carleton.gcrc.upload.UploadUtils;

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

  final static public String ATLAS_DESIGN_SERVER = "server";
  final static public String USER_DESIGN_AUTH = "_auth";

  final protected Logger logger = Logger.getLogger(this.getClass());
 
  private File configurationDirectory = null;
  private File fallbackConfigurationDirectory = null;
  private File rootDirectory = null;
  private File webInfDirectory = null;
  private String serverName = null;
  private CouchClient couchClient = null;
  private CouchDb couchDb = null;
  private CouchDesignDocument couchDd = null;
  private CouchDb configDb = null;
  private CouchDesignDocument configDesign = null;
  private String couchReplicationUserName = null;
  private String couchReplicationPassword = null;
  private UploadWorker uploadWorker = null;
  private ReplicationWorker replicationWorker = null;
  private ConfigWorker configWorker = null;
  private MailNotification mailNotification = null;
 
  public ConfigServlet() {
   
  }

  public void init(ServletConfig config) throws ServletException {
    super.init(config);
   
    logger.info("Initializing Couch Configuration");
   
    ServletContext servletContext = config.getServletContext();

    // Figure out configuration directories
    try {
      computeConfigurationDirectories(servletContext);
    } catch(ServletException e) {
      logger.error("Error while computing configuration directories",e);
      throw e;
    }
   
    // Instantiate CouchDb client
    try {
      initCouchDbClient(servletContext);
    } catch(ServletException e) {
      logger.error("Error while initializing couch client",e);
      throw e;
    }
   
    // Upload design documents for atlas server
    try {
      initAtlasServerDesignDocument(servletContext);
    } catch(ServletException e) {
      logger.error("Error while initializing design document for atlas server",e);
      throw e;
    }
   
    // Upload design documents for user auth
    try {
      initAuthDesignDocument(servletContext);
    } catch(ServletException e) {
      logger.error("Error while initializing design document for user auth",e);
      throw e;
    }
   
    // Upload documents to database
    try {
      initDatabaseDocuments(servletContext);
    } catch(ServletException e) {
      logger.error("Error while initializing design document for atlas server",e);
      throw e;
    }
   
    // Configure replication worker
    try {
      initReplicationWorker(servletContext);
    } catch(ServletException e) {
      logger.error("Error while initializing replication worker",e);
      throw e;
    }
   
    // Configure config listeners
    try {
      initCouchConfigListener(servletContext);
    } catch(ServletException e) {
      logger.error("Error while initializing couch config listener",e);
      throw e;
    }
   
    // Configure multimedia
    try {
      initMultimedia(servletContext);
    } catch(ServletException e) {
      logger.error("Error while initializing multimedia",e);
      throw e;
    }

    // Configure mail notification
    try {
      initMail(servletContext);
    } catch(ServletException e) {
      logger.error("Error while initializing mail notification",e);
      mailNotification = new MailNotificationNull();
    }
   
    // Configure upload
    try {
      initUpload(servletContext);
    } catch(ServletException e) {
      logger.error("Error while initializing upload",e);
      throw e;
    }
   
    // Upload logs on startup
    try {
      uploadLogs(servletContext);
    } catch(ServletException e) {
      logger.error("Error while uploading logs",e);
    }
   
    logger.info("Completed Couch Configuration");
  }

  private Properties loadProperties(String baseName, boolean loadDefault) throws ServletException {

    // Load up contribution properties file....
    Properties props = null;
    {
      File propFile = new File(configurationDirectory, baseName);
      if( false == propFile.exists() || false == propFile.isFile() ) {
        propFile = null;
      }
      if( null == propFile ) {
        propFile = new File(fallbackConfigurationDirectory, baseName);
        if( false == propFile.exists() || false == propFile.isFile() ) {
          propFile = null;
        }
      }
      if( loadDefault && null == propFile ) {
        propFile = new File(fallbackConfigurationDirectory, baseName+".default");
        if( false == propFile.exists() || false == propFile.isFile() ) {
          propFile = null;
        }
      }
      if( null == propFile ) {
        logger.error("Property file location can not be determined for: "+baseName);
      } else {
        logger.info("Reading properties from "+propFile.getAbsolutePath());
        FileInputStream fis = null;
        try {
          fis = new FileInputStream(propFile);
          props = new Properties();
          props.load(fis);
        } catch (Exception e) {
          logger.error("Unable to read properties from "+propFile.getAbsolutePath(),e);
          props = null;
        } finally {
          if( null != fis ) {
            try {
              fis.close();
            } catch (Exception e) {
              // Ignore
            }
          }
        }
      }
    }
   
    return props;
  }
 
  private void computeConfigurationDirectories(ServletContext servletContext) throws ServletException {
   
    if( null == servletContext ) {
      throw new ServletException("No servlet context provided");
    }
   
    // Parse environment variables
    {
      Map<String,String> envMap = System.getenv();
      for(String variable : envMap.keySet()) {
        String value = envMap.get(variable);
       
        //logger.info("env("+variable+"):"+value);
       
        if( "NUNALIIT_CONF_DIR".equalsIgnoreCase(variable) ) {
          File atlasConfigDir = new File(value);
          if( atlasConfigDir.exists() && atlasConfigDir.isDirectory() ) {
            // OK
            configurationDirectory = atlasConfigDir;
          } else {
            logger.error("Configuration directory associated with environment varible not found. Ignoring. "+atlasConfigDir.getAbsolutePath());
          }
        }
      }
    }
   
    // Find root directory
    {
      if( null != servletContext ) {
        String rootString = servletContext.getRealPath(".");
        rootDirectory = new File(rootString);
        if( false == rootDirectory.exists() ) {
          throw new ServletException("Can not find root directory");
        }
      }
    }
   
    // Find WEB-INF directory
    {
      if( null != servletContext ) {
        String webInfString = servletContext.getRealPath("./WEB-INF");
        webInfDirectory = new File(webInfString);
        if( false == webInfDirectory.exists() ) {
          throw new ServletException("Can not find WEB-INF directory");
        }
      }
    }
   
    // Look for ./WEB-INF/atlas.properties or ./WEB-INF/atlas.properties.default
    {
      File atlasPropsFile = new File(webInfDirectory, "atlas.properties");
      if( false == atlasPropsFile.exists()
       || false == atlasPropsFile.isFile() ) {
        atlasPropsFile = null;
      }
      if( null == atlasPropsFile ) {
        atlasPropsFile = new File(webInfDirectory, "atlas.properties.default");
        if( false == atlasPropsFile.exists()
         || false == atlasPropsFile.isFile() ) {
          atlasPropsFile = null;
        }
      }
      if( null != atlasPropsFile ) {
        // Read in properties
        Properties atlasProps = new Properties();
        logger.info("Reading atlas properties from "+atlasPropsFile.getAbsolutePath());
        FileInputStream fis = null;
        try {
          fis = new FileInputStream(atlasPropsFile);
          atlasProps.load(fis);
        } catch (Exception e) {
          logger.error("Unable to read atlas properties from "+atlasPropsFile.getAbsolutePath(),e);
        } finally {
          if( null != fis ) {
            try {
              fis.close();
            } catch (Exception e) {
              // Ignore
            }
          }
        }
       
        // Look for atlas.config.dir
        if( null == configurationDirectory
         && atlasProps.containsKey("atlas.config.dir") ) {
          String atlasConfigDirString = atlasProps.getProperty("atlas.config.dir");
          logger.info("Atlas config directory specified: "+atlasConfigDirString);
          File atlasConfigDir = new File(atlasConfigDirString);
          if( atlasConfigDir.exists() && atlasConfigDir.isDirectory() ) {
            // OK
            configurationDirectory = atlasConfigDir;
          } else {
            logger.error("Invalid configuration directory specified. Ignoring.");
          }
        }
       
        // Look for atlas.name
        if( atlasProps.containsKey("atlas.name") ) {
          String atlasName = atlasProps.getProperty("atlas.name");
          logger.info("Atlas name specified: "+atlasName);
          if( null == configurationDirectory ) {
            File atlasConfigDir = new File("/etc/nunaliit2",atlasName);
            File atlasConfigLegacyDir = new File("/etc/nunaliit2/couchdb",atlasName);
            if( atlasConfigDir.exists()
             && atlasConfigDir.isDirectory() ) {
              // OK
              configurationDirectory = atlasConfigDir;
            } else if( atlasConfigLegacyDir.exists()
                && atlasConfigLegacyDir.isDirectory() ) {
              // OK
              configurationDirectory = atlasConfigLegacyDir;
            } else {
              logger.error("Configuration directory associated with name not found. Ignoring. "+atlasConfigDir.getAbsolutePath());
            }
          }
        }
      }
    }
   
    // Fall back on WEB-INF directory
    {
      fallbackConfigurationDirectory = webInfDirectory;
    }

    if( null == configurationDirectory ) {
      configurationDirectory = fallbackConfigurationDirectory;
    }
   
    if( null == configurationDirectory ) {
      throw new ServletException("Can not determine configuration directory");
    }
    if( null == fallbackConfigurationDirectory ) {
      throw new ServletException("Can not determine fallback configuration directory");
    }
   
    logger.info("Configuration directory: "+configurationDirectory.getAbsolutePath());
    logger.info("Configuration directory on fallback: "+fallbackConfigurationDirectory.getAbsolutePath());
  }

  private void initCouchDbClient(ServletContext servletContext) throws ServletException {
   
    // Load up configuration information
    Properties props = loadProperties("couch.properties", false);
   
    // Our user is the admin user
    if( props.containsKey("couchdb.admin.user") ) {
      props.setProperty("couchdb.user", props.getProperty("couchdb.admin.user"));
    }
    if( props.containsKey("couchdb.admin.password") ) {
      props.setProperty("couchdb.password", props.getProperty("couchdb.admin.password"));
    }
   
    // Read couch db replication information
    if( props.containsKey("couchdb.replication.user") ) {
      couchReplicationUserName = props.getProperty("couchdb.replication.user");
    }
    if( props.containsKey("couchdb.replication.password") ) {
      couchReplicationPassword = props.getProperty("couchdb.replication.password");
    }
   
    // Create Couch Server from properties
    CouchFactory factory = new CouchFactory();
    try {
      couchClient = factory.getClient(props);
     
    } catch(Exception e) {
      logger.error("Unable to get Couch Server",e);
      throw new ServletException("Unable to get Couch Server",e);
    }
   
    // Create database
    try {
      if( props.containsKey("couchdb.dbUrl") ) {
        couchDb = factory.getDb(couchClient, props.getProperty("couchdb.dbUrl"));
      } else if( props.containsKey("couchdb.dbName") ) {
        couchDb = couchClient.getDatabase(props.getProperty("couchdb.dbName"));
      } else {
        throw new Exception("dbUrl or dbName must be provided");
      }
    } catch(Exception e) {
      logger.error("Unable to build Couch Database",e);
      throw new ServletException("Unable to build Couch Database",e);
    }
    logger.info("CouchDb configured: "+couchDb.getUrl());
  }

  private void initAtlasServerDesignDocument(ServletContext servletContext) throws ServletException {
    // Find root directory for design document
    File ddDir = null;
    {
      ddDir = new File(webInfDirectory, "uploadDesignDoc");
      if( false == ddDir.exists() || false == ddDir.isDirectory() ) {
        ddDir = null;
      }
      if( null == ddDir ) {
        throw new ServletException("Unable to find design document source for upload");
      }
    }

    try {
      DesignDocumentPush ddPush = new DesignDocumentPush(couchDb, ATLAS_DESIGN_SERVER, ddDir);
      ddPush.push();
    } catch(Exception e) {
      throw new ServletException("Problem pushing design document: "+ATLAS_DESIGN_SERVER, e);
    }
   
    try {
      couchDd = couchDb.getDesignDocument(ATLAS_DESIGN_SERVER);
    } catch (Exception e) {
      throw new ServletException("Unable to get design document", e);
    }
  }

  private void initAuthDesignDocument(ServletContext servletContext) throws ServletException {
    // Find root directory for design document
    File ddDir = null;
    {
      ddDir = new File(webInfDirectory, "userDesignAuth");
      if( false == ddDir.exists() || false == ddDir.isDirectory() ) {
        ddDir = null;
      }
      if( null == ddDir ) {
        throw new ServletException("Unable to find design document source for user auth");
      }
    }
   
    try {
      CouchDb userDb = couchClient.getDatabase("_users");
      DesignDocumentPush ddPush = new DesignDocumentPush(userDb, USER_DESIGN_AUTH, ddDir);
      ddPush.push();
    } catch(Exception e) {
      throw new ServletException("Problem pushing design document: "+USER_DESIGN_AUTH, e);
    }
  }

  private void initDatabaseDocuments(ServletContext servletContext) throws ServletException {
    // Find root directory for initializing documents
    {
      File documentsDir = null;
      {
        documentsDir = new File(webInfDirectory, "initializeDocs");
        if( false == documentsDir.exists() || false == documentsDir.isDirectory() ) {
          documentsDir = null;
        }
      }
     
      if( null == documentsDir ) {
        logger.error("Unable to find document directory for initializing");
      } else {
        String[] fileNames = documentsDir.list();
        for(String fileName : fileNames) {
          File file = new File(documentsDir, fileName);
   
          try {
            DocumentInitialize docInitialize = new DocumentInitialize(couchDb, file);
            docInitialize.upload();
          } catch(Exception e) {
            throw new ServletException("Problem pushing document: "+file.getAbsolutePath(), e);
          }
        }
      }
    }
   
    // Find root directory for updating documents
    {
      File documentsDir = null;
      {
        documentsDir = new File(webInfDirectory, "updateDocs");
        if( false == documentsDir.exists() || false == documentsDir.isDirectory() ) {
          documentsDir = null;
        }
      }
     
      if( null == documentsDir ) {
        logger.error("Unable to find document directory for updating");
      } else {
        String[] fileNames = documentsDir.list();
        for(String fileName : fileNames) {
          File file = new File(documentsDir, fileName);
   
          try {
            DocumentPush docPush = new DocumentPush(couchDb, file);
            docPush.push();
          } catch(Exception e) {
            throw new ServletException("Problem pushing document: "+file.getAbsolutePath(), e);
          }
        }
      }
    }
  }

  private void initReplicationWorker(ServletContext servletContext) throws ServletException {

    if( null == couchClient ) {
      throw new ServletException("Replication worker requires a CouchDb client");
    }
   
    try {
      replicationWorker = new ReplicationWorker();
      replicationWorker.setCouchClient(couchClient);
      replicationWorker.start();
     
    } catch (Exception e) {
      throw new ServletException("Error starting replication worker",e);
    }
  }

  private void initCouchConfigListener(ServletContext servletContext) throws ServletException {
   
    // Load up configuration information
    Properties props = loadProperties("config.properties", true);
   
    // Interpret configuration
    serverName = props.getProperty("config.serverName");
    String dbName = props.getProperty("config.dbName");

    if( null == serverName ) {
      throw new ServletException("Can not determine server name for querying configuration information");
    }
    if( null == dbName ) {
      throw new ServletException("Can not determine database name for querying configuration information");
    }
   
    logger.info("Server Name: "+serverName);
   
    try {
      configDb = couchClient.getDatabase(dbName);
      configDesign = configDb.getDesignDocument("config");
     
      ConfigListenerCollection configListener = new ConfigListenerCollection();
      List<ConfigListener> collection = new Vector<ConfigListener>();
      collection.add( new ReplicationConfigListener(
          couchReplicationUserName
          ,couchReplicationPassword
          ,replicationWorker
          ) );
      configListener.setCollection(collection);

      configWorker = new ConfigWorker();
      configWorker.setDesignDocument(configDesign);
      configWorker.setServerName(serverName);
      configWorker.setConfigListener(configListener);
      configWorker.start();
     
    } catch (Exception e) {
      throw new ServletException("Error starting config listener worker",e);
    }
   
    logger.info("CouchDb configured: "+couchDb.getUrl());
  }

  private void initMultimedia(ServletContext servletContext) throws ServletException {
   
    // Load up configuration information
    Properties props = loadProperties("multimedia.properties", true);
   
    MultimediaConfiguration.configureFromProperties(props);
  }

  private void initMail(ServletContext servletContext) throws ServletException {
   
    // Load up configuration information
    Properties props = loadProperties("mail.properties", true);
   
    // Create mail notification
    MailNotificationImpl mail = null;
    try {
      mail = new MailNotificationImpl();
      mail.setMailProperties(props);
     
    } catch(Exception e) {
      logger.error("Unable to configure mail notification",e);
    }

    mailNotification = mail;
  }

  private void initUpload(ServletContext servletContext) throws ServletException {
   
    Properties props = loadProperties("upload.properties", true);
    servletContext.setAttribute(UploadUtils.PROPERTIES_ATTRIBUTE, props);

    // Repository directory (this is where files are sent to)
    File repositoryDir = UploadUtils.getMediaDir(servletContext);
   
    UploadListener uploadListener = new UploadListener(couchDd,repositoryDir);
    servletContext.setAttribute(UploadServlet.OnUploadedListenerAttributeName, uploadListener);
    OnUploadedListenerSingleton.configure(uploadListener);
   
    try {
      UploadWorkerSettings settings = new UploadWorkerSettings(props);
     
      uploadWorker = new UploadWorker(settings);
      uploadWorker.setDesignDocument(couchDd);
      uploadWorker.setMediaDir(repositoryDir);
      uploadWorker.setMailNotification(mailNotification);
      uploadWorker.addConversionPlugin( new MultimediaFileConverter(props) );
      uploadWorker.addConversionPlugin( new GpxFileConverter() );
      uploadWorker.start();
    } catch (Exception e) {
      logger.error("Error starting upload worker",e);
      throw new ServletException("Error starting upload worker",e);
    }
  }

  private void uploadLogs(ServletContext servletContext) throws ServletException {
    // Load up configuration information
    Properties props = loadProperties("install.properties", true);
   
    if( false == props.containsKey("cron.working.dir") ) {
      logger.error("Property cron.working.dir not set in install.properties. Not uploading logs.");
      return;
    }
   
    // See if directory where CRON scripts are located can be found
    File workingDir = new File( props.getProperty("cron.working.dir") );
    File cronDir = new File(workingDir,"cron");
    if( false == cronDir.exists() || false == cronDir.isDirectory() ) {
      logger.error("Can not find cron directory at: "+cronDir.getAbsolutePath()+". Not uploading logs.");
      return;
    }
   
    // See if CRON logs are present
    File cronLogFile = new File(cronDir, "cron.log");
    if( false == cronLogFile.exists() || false == cronLogFile.isFile() ) {
      logger.error("Can not find cron log file at: "+cronLogFile.getAbsolutePath()+". Not uploading logs.");
      return;
    }
   
    CouchConfigFactory factory = new CouchConfigFactory();
    factory.setServerName(serverName);
    factory.setConfigDesign(configDesign);
    CouchConfig couchConfig = null;
    try {
      couchConfig = factory.retrieveConfigurationObject();
    } catch (Exception e) {
      logger.error("Can not load configuration object. Not uploading logs.",e);
      return;
    }

    try {
      couchConfig.uploadCronLogs(cronLogFile);
      logger.info("cron.log uploaded to configuration object");
    } catch (Exception e) {
      logger.error("Error while uploading cron logs. Not uploading logs.",e);
      return;
    }
  }
 
  public void destroy() {
    try {
      uploadWorker.stopTimeoutMillis(5*1000); // 5 seconds
    } catch (Exception e) {
      logger.error("Unable to shutdown upload worker", e);
    }

    try {
      configWorker.stopTimeoutMillis(5*1000); // 5 seconds
    } catch (Exception e) {
      logger.error("Unable to shutdown config listener worker", e);
    }

    try {
      replicationWorker.stopTimeoutMillis(5*1000); // 5 seconds
    } catch (Exception e) {
      logger.error("Unable to shutdown replication worker", e);
    }
  }
}
TOP

Related Classes of ca.carleton.gcrc.couch.config.ConfigServlet

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.