public void start()
      throws DatabaseInitException, BimserverDatabaseException, PluginException,
          DatabaseRestartRequiredException, ServerException {
    try {
      LOGGER.debug("Starting BIMserver");
      SVersion localVersion = versionChecker.getLocalVersion();
      if (localVersion != null) {
        LOGGER.info(
            "Version: "
                + localVersion.getMajor()
                + "."
                + localVersion.getMinor()
                + "."
                + localVersion.getRevision()
                + " - "
                + localVersion.getDate());
      } else {
        LOGGER.info("Unknown version");
      }

      try {
        pluginManager.addPluginChangeListener(
            new PluginChangeListener() {
              @Override
              public void pluginStateChanged(PluginContext pluginContext, boolean enabled) {
                // Reflect this change also in the database
                Condition pluginCondition =
                    new AttributeCondition(
                        StorePackage.eINSTANCE.getPluginDescriptor_PluginClassName(),
                        new StringLiteral(pluginContext.getPlugin().getClass().getName()));
                DatabaseSession session = bimDatabase.createSession();
                try {
                  Map<Long, PluginDescriptor> pluginsFound =
                      session.query(pluginCondition, PluginDescriptor.class, Query.getDefault());
                  if (pluginsFound.size() == 0) {
                    LOGGER.error(
                        "Error changing plugin-state in database, plugin "
                            + pluginContext.getPlugin().getClass().getName()
                            + " not found");
                  } else if (pluginsFound.size() == 1) {
                    PluginDescriptor pluginConfiguration = pluginsFound.values().iterator().next();
                    pluginConfiguration.setEnabled(pluginContext.isEnabled());
                    session.store(pluginConfiguration);
                  } else {
                    LOGGER.error(
                        "Error, too many plugin-objects found in database for name "
                            + pluginContext.getPlugin().getClass().getName());
                  }
                  session.commit();
                } catch (BimserverDatabaseException e) {
                  LOGGER.error("", e);
                } catch (ServiceException e) {
                  LOGGER.error("", e);
                } finally {
                  session.close();
                }
              }
            });
        pluginManager.loadPlugin(
            ObjectIDMPlugin.class,
            new File(".").toURI(),
            "Internal",
            new SchemaFieldObjectIDMPlugin(),
            getClass().getClassLoader(),
            PluginSourceType.INTERNAL,
            null);
      } catch (Exception e) {
        LOGGER.error("", e);
      }

      try {
        metaDataManager.init();
        pluginManager.initAllLoadedPlugins();
      } catch (PluginException e) {
        LOGGER.error("", e);
      }
      serverStartTime = new GregorianCalendar();

      longActionManager = new LongActionManager();

      Set<EPackage> packages = new LinkedHashSet<>();
      packages.add(Ifc2x3tc1Package.eINSTANCE);
      packages.add(Ifc4Package.eINSTANCE);
      templateEngine = new TemplateEngine();
      templateEngine.init(config.getResourceFetcher().getResource("templates/"));
      Path databaseDir = config.getHomeDir().resolve("database");
      BerkeleyKeyValueStore keyValueStore = new BerkeleyKeyValueStore(databaseDir);

      schemaConverterManager.registerConverter(new Ifc2x3tc1ToIfc4SchemaConverterFactory());
      schemaConverterManager.registerConverter(new Ifc4ToIfc2x3tc1SchemaConverterFactory());

      metricsRegistry = new MetricsRegistry();

      Query.setPackageMetaDataForDefaultQuery(metaDataManager.getPackageMetaData("store"));

      bimDatabase = new Database(this, packages, keyValueStore, metaDataManager);
      try {
        bimDatabase.init();
      } catch (DatabaseRestartRequiredException e) {
        bimDatabase.close();
        keyValueStore = new BerkeleyKeyValueStore(databaseDir);
        bimDatabase = new Database(this, packages, keyValueStore, metaDataManager);
        try {
          bimDatabase.init();
        } catch (InconsistentModelsException e1) {
          LOGGER.error("", e);
          serverInfoManager.setServerState(ServerState.FATAL_ERROR);
          serverInfoManager.setErrorMessage("Inconsistent models");
        }
      } catch (InconsistentModelsException e) {
        LOGGER.error("", e);
        serverInfoManager.setServerState(ServerState.FATAL_ERROR);
        serverInfoManager.setErrorMessage("Inconsistent models");
      }

      DatabaseSession encsession = bimDatabase.createSession();
      try {
        byte[] encryptionkeyBytes = null;
        if (!bimDatabase.getRegistry().has(ENCRYPTIONKEY, encsession)) {
          encryptionkeyBytes = new byte[16];
          new SecureRandom().nextBytes(encryptionkeyBytes);
          bimDatabase.getRegistry().save(ENCRYPTIONKEY, encryptionkeyBytes, encsession);
          encsession.commit();
        } else {
          encryptionkeyBytes = bimDatabase.getRegistry().readByteArray(ENCRYPTIONKEY, encsession);
        }
        encryptionkey = new SecretKeySpec(encryptionkeyBytes, "AES");
      } finally {
        encsession.close();
      }

      protocolBuffersMetaData = new ProtocolBuffersMetaData();
      protocolBuffersMetaData.load(servicesMap, ProtocolBuffersBimServerClientFactory.class);

      serverInfoManager.init(this);

      webModuleManager = new WebModuleManager(this);

      jsonHandler = new JsonHandler(this);

      serializerFactory = new SerializerFactory();
      deserializerFactory = new DeserializerFactory();

      serverSettingsCache = new ServerSettingsCache(bimDatabase);

      serverInfoManager.update();

      if (serverInfoManager.getServerState() == ServerState.MIGRATION_REQUIRED) {
        serverInfoManager.registerStateChangeListener(
            new StateChangeListener() {
              @Override
              public void stateChanged(ServerState oldState, ServerState newState) {
                if (oldState == ServerState.MIGRATION_REQUIRED && newState == ServerState.RUNNING) {
                  try {
                    initDatabaseDependantItems();
                  } catch (BimserverDatabaseException e) {
                    LOGGER.error("", e);
                  }
                }
              }
            });
      } else {
        initDatabaseDependantItems();
      }

      mailSystem = new MailSystem(this);

      diskCacheManager = new DiskCacheManager(this, config.getHomeDir().resolve("cache"));

      mergerFactory = new MergerFactory(this);

      FileBasedReflectorFactoryBuilder factoryBuilder = new FileBasedReflectorFactoryBuilder();
      reflectorFactory = factoryBuilder.newReflectorFactory();
      if (reflectorFactory == null) {
        throw new RuntimeException("No reflector factory!");
      }
      servicesMap.setReflectorFactory(reflectorFactory);

      bimScheduler = new JobScheduler(this);
      bimScheduler.start();

      if (config.isStartEmbeddedWebServer()) {
        embeddedWebServer.start();
      }

      if (config.isStartCommandLine()) {
        commandLine = new CommandLine(this);
        commandLine.start();
      }
    } catch (Throwable e) {
      LOGGER.error("", e);
      serverInfoManager.setErrorMessage(e.getMessage());
    }
  }
  /**
   * Create a new BIMserver
   *
   * @param homeDir A directory where the user can store instance specific configuration files
   * @param resourceFetcher A resource fetcher
   */
  public BimServer(BimServerConfig config) {
    this.config = config;
    try {
      if (config.getHomeDir() != null) {
        initHomeDir();
      }

      fixLogging();
      UncaughtExceptionHandler uncaughtExceptionHandler =
          new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
              if (e instanceof OutOfMemoryError) {
                serverInfoManager.setOutOfMemory();
                LOGGER.error("", e);
              } else if (e instanceof Error) {
                serverInfoManager.setErrorMessage(e.getMessage());
                LOGGER.error("", e);
              } else {
                LOGGER.error("", e);
              }
            }
          };

      Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
      LOGGER = LoggerFactory.getLogger(BimServer.class);

      LOGGER.info("Starting BIMserver");
      if (config.getHomeDir() != null) {
        LOGGER.info("Using \"" + config.getHomeDir().toString() + "\" as homedir");
      } else {
        LOGGER.info("Not using a homedir");
      }

      servicesMap = InterfaceList.createSServicesMap();
      LOGGER.debug("SServiceMap Created");

      jsonSocketReflectorFactory = new JsonSocketReflectorFactory(servicesMap);
      LOGGER.debug("JsonSocketReflectorFactory created");

      serverInfoManager = new ServerInfoManager();
      LOGGER.debug("ServerInfoManager created");

      notificationsManager = new NotificationsManager(this, jsonSocketReflectorFactory);
      LOGGER.debug("NotificationsManager created");

      internalServicesManager =
          new InternalServicesManager(this, notificationsManager.getSiteAddress());
      LOGGER.debug("InternalServicesManager created");

      serviceFactory = new PublicInterfaceFactory(this);
      LOGGER.debug("PublicInterfaceFactory created");

      pluginManager =
          new PluginManager(
              config.getHomeDir().resolve("tmp"),
              config.getClassPath(),
              serviceFactory,
              internalServicesManager,
              servicesMap);
      metaDataManager = new MetaDataManager(pluginManager);
      pluginManager.setMetaDataManager(metaDataManager);
      LOGGER.debug("PluginManager created");

      versionChecker = new VersionChecker(config.getResourceFetcher());
      LOGGER.debug("Version Checker created");

      compareCache = new CompareCache();
      LOGGER.debug("Compare cache created");
      if (config.isStartEmbeddedWebServer()) {
        embeddedWebServer = new EmbeddedWebServer(this, config.isLocalDev());
        LOGGER.debug("Embedded webserver created");
      }

      LOGGER.debug("Done with initial setup");
    } catch (Throwable e) {
      if (LOGGER == null) {
        e.printStackTrace();
      } else {
        LOGGER.error("", e);
      }
      serverInfoManager.setErrorMessage(e.getMessage());
    }
  }