/** Close OpenKM and free resources */
  public static synchronized void stop(GenericServlet gs) {
    if (!running) {
      throw new IllegalStateException("OpenKM not started");
    }

    // Shutdown plugin framework
    ExtensionManager.getInstance().shutdown();

    try {
      if (!Config.SYSTEM_OPENOFFICE_PATH.equals("")) {
        if (log == null && gs != null) {
          gs.log("*** Shutting down OpenOffice manager ***");
        } else {
          log.info("*** Shutting down OpenOffice manager ***");
        }

        DocConverter.getInstance().stop();
      }
    } catch (Throwable e) {
      log.warn(e.getMessage(), e);
    }

    if (hasConfiguredDataStore) {
      if (log == null && gs != null)
        gs.log("*** Shutting down datastore garbage collection... ***");
      else log.info("*** Shutting down datastore garbage collection... ***");
      dsgc.cancel();
    }

    if (Config.SCHEDULE_MAIL_IMPORTER > 0) {
      if (log == null && gs != null) gs.log("*** Shutting down user mail importer ***");
      else log.info("*** Shutting down user mail importer ***");
      umi.cancel();
    }

    if (Config.MANAGED_TEXT_EXTRACTION_SCHEDULE > 0) {
      if (log == null && gs != null) gs.log("*** Shutting down text extractor worker ***");
      else log.info("*** Shutting down text extractor worker ***");
      tew.cancel();
    }

    if (log == null && gs != null) gs.log("*** Shutting down repository info... ***");
    else log.info("*** Shutting down repository info... ***");
    ri.cancel();

    if (log == null && gs != null) gs.log("*** Shutting down UI Notification... ***");
    else log.info("*** Shutting down UI Notification... ***");
    uin.cancel();

    if (log == null && gs != null) gs.log("*** Shutting down cron... ***");
    else log.info("*** Shutting down cron... ***");
    cron.cancel();

    if (log == null && gs != null) gs.log("*** Shutting down watchdog... ***");
    else log.info("*** Shutting down watchdog... ***");
    wd.cancel();

    if (Config.UPDATE_INFO) {
      if (log == null && gs != null) gs.log("*** Shutting down update info... ***");
      else log.info("*** Shutting down update info... ***");
      ui.cancel();
    }

    // Cancel timers
    dsgcTimer.cancel();
    umiTimer.cancel();
    riTimer.cancel();
    cronTimer.cancel();
    uinTimer.cancel();
    wdTimer.cancel();
    uiTimer.cancel();
    tewTimer.cancel();

    if (log == null && gs != null) gs.log("*** Shutting down repository... ***");
    else log.info("*** Shutting down repository... ***");

    if (Config.USER_ITEM_CACHE) {
      // Serialize
      try {
        log.info("*** Cache serialization ***");
        UserItemsManager.serialize();
        UserNodeKeywordsManager.serialize();
      } catch (DatabaseException e) {
        log.warn(e.getMessage(), e);
      }
    }

    try {
      // Preserve system user config
      if (!Config.REPOSITORY_NATIVE) {
        JcrRepositoryModule.shutdown();
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }

    if (log == null && gs != null) gs.log("*** Repository shutted down ***");
    else log.info("*** Repository shutted down ***");

    try {
      if (log == null && gs != null) gs.log("*** Ejecute stop script ***");
      else log.info("*** Ejecute stop script ***");
      File script = new File(Config.HOME_DIR + File.separatorChar + Config.STOP_SCRIPT);
      ExecutionUtils.runScript(script);
      File jar = new File(Config.HOME_DIR + File.separatorChar + Config.STOP_JAR);
      ExecutionUtils.getInstance().runJar(jar);
    } catch (Throwable e) {
      log.warn(e.getMessage(), e);
    }

    if (log == null && gs != null) gs.log("*** Shutting down workflow engine... ***");
    else log.info("*** Shutting down workflow engine... ***");
    JbpmContext jbpmContext = JBPMUtils.getConfig().createJbpmContext();
    jbpmContext.getJbpmConfiguration().getJobExecutor().stop();
    jbpmContext.getJbpmConfiguration().close();
    jbpmContext.close();

    // OpenKM is stopped
    running = false;
  }
  /** Start OpenKM and possible repository and database initialization */
  public static synchronized void start() throws ServletException {
    SystemAuthentication systemAuth = new SystemAuthentication();

    if (running) {
      throw new IllegalStateException("OpenKM already started");
    }

    try {
      log.info("*** Repository initializing... ***");

      if (Config.REPOSITORY_NATIVE) {
        systemAuth.enable();
        DbRepositoryModule.initialize();
        systemAuth.disable();
      } else {
        JcrRepositoryModule.initialize();
      }

      log.info("*** Repository initialized ***");
    } catch (Exception e) {
      throw new ServletException(e.getMessage(), e);
    }

    if (Config.USER_ITEM_CACHE) {
      // Deserialize
      try {
        log.info("*** Cache deserialization ***");
        UserItemsManager.deserialize();
        UserNodeKeywordsManager.deserialize();
      } catch (DatabaseException e) {
        log.warn(e.getMessage(), e);
      }
    }

    log.info("*** User database initialized ***");

    if (!Config.REPOSITORY_NATIVE) {
      // Test for datastore
      SessionImpl si = (SessionImpl) JcrRepositoryModule.getSystemSession();

      if (((RepositoryImpl) si.getRepository()).getDataStore() == null) {
        hasConfiguredDataStore = false;
      } else {
        hasConfiguredDataStore = true;
      }
    }

    // Create timers
    uiTimer = new Timer("Update Info");
    wdTimer = new Timer("Session Watchdog");
    cronTimer = new Timer("Crontab Manager");
    uinTimer = new Timer("User Interface Notification");
    riTimer = new Timer("Repository Info", true);
    umiTimer = new Timer("User Mail Importer");
    dsgcTimer = new Timer("Datastore Garbage Collector");
    tewTimer = new Timer("Text Extractor Worker", true);

    // Workflow
    log.info("*** Initializing workflow engine... ***");
    JbpmContext jbpmContext = JBPMUtils.getConfig().createJbpmContext();
    jbpmContext.setSessionFactory(HibernateUtil.getSessionFactory());
    jbpmContext.getGraphSession();
    jbpmContext.getJbpmConfiguration().getJobExecutor().start(); // startJobExecutor();
    jbpmContext.close();

    // Mime types
    log.info("*** Initializing MIME types... ***");
    MimeTypeConfig.loadMimeTypes();

    if (Config.UPDATE_INFO) {
      log.info("*** Activating update info ***");
      ui = new UpdateInfo();
      uiTimer.schedule(ui, 1000, 24 * 60 * 60 * 1000); // First in 1 seg, next each 24 hours
    }

    log.info("*** Activating watchdog ***");
    wd = new Watchdog();
    wdTimer.schedule(wd, 60 * 1000, 5 * 60 * 1000); // First in 1 min, next each 5 mins

    log.info("*** Activating cron ***");
    cron = new Cron();
    Calendar calCron = Calendar.getInstance();
    calCron.add(Calendar.MINUTE, 1);
    calCron.set(Calendar.SECOND, 0);
    calCron.set(Calendar.MILLISECOND, 0);

    // Round begin to next minute, 0 seconds, 0 miliseconds
    cronTimer.scheduleAtFixedRate(
        cron, calCron.getTime(), 60 * 1000); // First in 1 min, next each 1 min

    log.info("*** Activating UI Notification ***");
    uin = new UINotification();

    // First in 1 second next in x minutes
    uinTimer.scheduleAtFixedRate(
        uin, 1000, TimeUnit.MINUTES.toMillis(Config.SCHEDULE_UI_NOTIFICATION));

    log.info("*** Activating repository info ***");
    ri = new RepositoryInfo();

    // First in 1 min, next each X minutes
    riTimer.schedule(ri, 60 * 1000, TimeUnit.MINUTES.toMillis(Config.SCHEDULE_REPOSITORY_INFO));

    if (Config.MANAGED_TEXT_EXTRACTION_SCHEDULE > 0) {
      log.info("*** Activating text extractor worker ***");
      tew = new TextExtractorWorker();

      // First in 1 min, next each x minutes
      tewTimer.schedule(
          tew, 60 * 1000, TimeUnit.MINUTES.toMillis(Config.MANAGED_TEXT_EXTRACTION_SCHEDULE));
    }

    if (Config.SCHEDULE_MAIL_IMPORTER > 0) {
      log.info("*** Activating user mail importer ***");
      umi = new UserMailImporter();

      // First in 5 mins, next each x minutes
      umiTimer.schedule(
          umi, 5 * 60 * 1000, TimeUnit.MINUTES.toMillis(Config.SCHEDULE_MAIL_IMPORTER));
    } else {
      log.info("*** User mail importer disabled ***");
    }

    // Datastore garbage collection
    if (!Config.REPOSITORY_NATIVE && hasConfiguredDataStore) {
      log.info("*** Activating datastore garbage collection ***");
      dsgc = new DataStoreGarbageCollector();
      Calendar calGc = Calendar.getInstance();
      calGc.add(Calendar.DAY_OF_YEAR, 1);
      calGc.set(Calendar.HOUR_OF_DAY, 0);
      calGc.set(Calendar.MINUTE, 0);
      calGc.set(Calendar.SECOND, 0);
      calGc.set(Calendar.MILLISECOND, 0);
      dsgcTimer.scheduleAtFixedRate(
          dsgc, calGc.getTime(), 24 * 60 * 60 * 1000); // First tomorrow at 00:00, next
      // each 24 hours
    }

    try {
      log.info("*** Activating thesaurus repository ***");
      RDFREpository.getInstance();
    } catch (Exception e) {
      log.warn(e.getMessage(), e);
    }

    try {
      if (!Config.SYSTEM_OPENOFFICE_PATH.equals("")) {
        log.info("*** Start OpenOffice manager ***");
        DocConverter.getInstance().start();
      } else {
        log.warn("*** No OpenOffice manager configured ***");
      }
    } catch (Throwable e) {
      log.warn(e.getMessage(), e);
    }

    // Initialize plugin framework
    ExtensionManager.getInstance();

    try {
      log.info("*** Ejecute start script ***");
      File script = new File(Config.HOME_DIR + File.separatorChar + Config.START_SCRIPT);
      ExecutionUtils.runScript(script);
      File jar = new File(Config.HOME_DIR + File.separatorChar + Config.START_JAR);
      ExecutionUtils.getInstance().runJar(jar);
    } catch (Throwable e) {
      log.warn(e.getMessage(), e);
    }

    // OpenKM is started
    running = true;
  }