Package com.orientechnologies.orient.core

Source Code of com.orientechnologies.orient.core.Orient

/*
  *
  *  *  Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
  *  *
  *  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  *  you may not use this file except in compliance with the License.
  *  *  You may obtain a copy of the License at
  *  *
  *  *       http://www.apache.org/licenses/LICENSE-2.0
  *  *
  *  *  Unless required by applicable law or agreed to in writing, software
  *  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  *  See the License for the specific language governing permissions and
  *  *  limitations under the License.
  *  *
  *  * For more information: http://www.orientechnologies.com
  *
  */
package com.orientechnologies.orient.core;

import com.orientechnologies.common.io.OFileUtils;
import com.orientechnologies.common.io.OIOUtils;
import com.orientechnologies.common.listener.OListenerManger;
import com.orientechnologies.common.log.OLogManager;
import com.orientechnologies.common.parser.OSystemVariableResolver;
import com.orientechnologies.common.profiler.OProfiler;
import com.orientechnologies.common.profiler.OProfilerMBean;
import com.orientechnologies.orient.core.command.script.OScriptManager;
import com.orientechnologies.orient.core.config.OGlobalConfiguration;
import com.orientechnologies.orient.core.conflict.ORecordConflictStrategyFactory;
import com.orientechnologies.orient.core.db.ODatabaseFactory;
import com.orientechnologies.orient.core.db.ODatabaseLifecycleListener;
import com.orientechnologies.orient.core.db.ODatabaseThreadLocalFactory;
import com.orientechnologies.orient.core.engine.OEngine;
import com.orientechnologies.orient.core.engine.local.OEngineLocalPaginated;
import com.orientechnologies.orient.core.engine.memory.OEngineMemory;
import com.orientechnologies.orient.core.exception.OConfigurationException;
import com.orientechnologies.orient.core.record.ORecordFactoryManager;
import com.orientechnologies.orient.core.storage.OStorage;

import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Orient extends OListenerManger<OOrientListener> {
  public static final String                                                           ORIENTDB_HOME          = "ORIENTDB_HOME";
  public static final String                                                           URL_SYNTAX             = "<engine>:<db-type>:<db-name>[?<db-param>=<db-value>[&]]*";

  protected static final Orient                                                        instance               = new Orient();
  protected static boolean                                                             registerDatabaseByPath = false;

  protected final ConcurrentMap<String, OEngine>                                       engines                = new ConcurrentHashMap<String, OEngine>();
  protected final ConcurrentMap<String, OStorage>                                      storages               = new ConcurrentHashMap<String, OStorage>();

  protected final Map<ODatabaseLifecycleListener, ODatabaseLifecycleListener.PRIORITY> dbLifecycleListeners   = new LinkedHashMap<ODatabaseLifecycleListener, ODatabaseLifecycleListener.PRIORITY>();
  protected final ODatabaseFactory                                                     databaseFactory        = new ODatabaseFactory();
  protected final OScriptManager                                                       scriptManager          = new OScriptManager();
  protected final Timer                                                                timer                  = new Timer(true);
  protected final ThreadGroup                                                          threadGroup            = new ThreadGroup(
                                                                                                                  "OrientDB");
  protected final AtomicInteger                                                        serialId               = new AtomicInteger();
  private final ReadWriteLock                                                          engineLock             = new ReentrantReadWriteLock();
  protected ORecordFactoryManager                                                      recordFactoryManager   = new ORecordFactoryManager();
  protected ORecordConflictStrategyFactory                                             recordConflictStrategy = new ORecordConflictStrategyFactory();
  protected OrientShutdownHook                                                         shutdownHook;
  protected OProfilerMBean                                                             profiler               = new OProfiler();
  protected ODatabaseThreadLocalFactory                                                databaseThreadFactory;
  protected volatile boolean                                                           active                 = false;
  protected ThreadPoolExecutor                                                         workers;

  protected Orient() {
    super(true);

    startup();
  }

  public static Orient instance() {
    return instance;
  }

  public static String getHomePath() {
    String v = System.getProperty("orient.home");

    if (v == null)
      v = OSystemVariableResolver.resolveVariable(ORIENTDB_HOME);

    return OFileUtils.getPath(v);
  }

  public static String getTempPath() {
    return OFileUtils.getPath(System.getProperty("java.io.tmpdir") + "/orientdb/");
  }

  /**
   * Tells if to register database by path. Default is false. Setting to true allows to have multiple databases in different path
   * with the same name.
   *
   * @see #setRegisterDatabaseByPath(boolean)
   * @return
   */
  public static boolean isRegisterDatabaseByPath() {
    return registerDatabaseByPath;
  }

  /**
   * Register database by path. Default is false. Setting to true allows to have multiple databases in different path with the same
   * name.
   *
   * @param iValue
   */
  public static void setRegisterDatabaseByPath(final boolean iValue) {
    registerDatabaseByPath = iValue;
  }

  public ORecordConflictStrategyFactory getRecordConflictStrategy() {
    return recordConflictStrategy;
  }

  public Orient startup() {
    engineLock.writeLock().lock();
    try {
      if (active)
        // ALREADY ACTIVE
        return this;

      shutdownHook = new OrientShutdownHook();

      final int cores = Runtime.getRuntime().availableProcessors();

      workers = new ThreadPoolExecutor(cores, cores * 3, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(cores * 500) {
        @Override
        public boolean offer(Runnable e) {
          // turn offer() and add() into a blocking calls (unless interrupted)
          try {
            put(e);
            return true;
          } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
          }
          return false;
        }
      });

      // REGISTER THE EMBEDDED ENGINE
      registerEngine(new OEngineLocalPaginated());
      registerEngine(new OEngineMemory());
      registerEngine("com.orientechnologies.orient.client.remote.OEngineRemote");

      if (OGlobalConfiguration.PROFILER_ENABLED.getValueAsBoolean())
        // ACTIVATE RECORDING OF THE PROFILER
        profiler.startRecording();

      if (OGlobalConfiguration.ENVIRONMENT_DUMP_CFG_AT_STARTUP.getValueAsBoolean())
        OGlobalConfiguration.dumpConfiguration(System.out);

      active = true;
      return this;

    } finally {
      engineLock.writeLock().unlock();
    }
  }

  public Orient shutdown() {
    engineLock.writeLock().lock();
    try {
      if (!active)
        return this;

      active = false;

      workers.shutdown();

      OLogManager.instance().debug(this, "Orient Engine is shutting down...");

      // CALL THE SHUTDOWN ON ALL THE LISTENERS
      for (OOrientListener l : browseListeners()) {
        if (l != null)
          l.onShutdown();
      }

      closeAllStorages();

      // SHUTDOWN ENGINES
      for (OEngine engine : engines.values())
        engine.shutdown();
      engines.clear();

      if (databaseFactory != null)
        // CLOSE ALL DATABASES
        databaseFactory.shutdown();

      if (shutdownHook != null) {
        shutdownHook.cancel();
        shutdownHook = null;
      }

      if (threadGroup != null)
        // STOP ALL THE PENDING THREADS
        threadGroup.interrupt();

      resetListeners();

      timer.purge();

      profiler.shutdown();

      OLogManager.instance().info(this, "OrientDB Engine shutdown complete");
      OLogManager.instance().flush();

    } finally {
      engineLock.writeLock().unlock();
    }
    return this;
  }

  public void closeAllStorages() {
    engineLock.writeLock().lock();
    try {
      // CLOSE ALL THE STORAGES
      final List<OStorage> storagesCopy = new ArrayList<OStorage>(storages.values());
      for (OStorage stg : storagesCopy) {
        try {
          OLogManager.instance().info(this, "- storage: " + stg.getName() + "...");
          stg.close(true, false);
        } catch (Throwable e) {
          OLogManager.instance().warn(this, "-- error on closing storage", e);
        }
      }
      storages.clear();
    } finally {
      engineLock.writeLock().unlock();
    }
  }

  public ThreadPoolExecutor getWorkers() {
    return workers;
  }

  public OStorage loadStorage(String iURL) {
    if (iURL == null || iURL.length() == 0)
      throw new IllegalArgumentException("URL missed");

    if (iURL.endsWith("/"))
      iURL = iURL.substring(0, iURL.length() - 1);

    // SEARCH FOR ENGINE
    int pos = iURL.indexOf(':');
    if (pos <= 0)
      throw new OConfigurationException("Error in database URL: the engine was not specified. Syntax is: " + URL_SYNTAX
          + ". URL was: " + iURL);

    final String engineName = iURL.substring(0, pos);

    engineLock.readLock().lock();
    try {
      final OEngine engine = engines.get(engineName.toLowerCase());

      if (engine == null)
        throw new OConfigurationException("Error on opening database: the engine '" + engineName + "' was not found. URL was: "
            + iURL + ". Registered engines are: " + engines.keySet());

      // SEARCH FOR DB-NAME
      iURL = iURL.substring(pos + 1);
      pos = iURL.indexOf('?');

      Map<String, String> parameters = null;
      String dbPath = null;
      if (pos > 0) {
        dbPath = iURL.substring(0, pos);
        iURL = iURL.substring(pos + 1);

        // PARSE PARAMETERS
        parameters = new HashMap<String, String>();
        String[] pairs = iURL.split("&");
        String[] kv;
        for (String pair : pairs) {
          kv = pair.split("=");
          if (kv.length < 2)
            throw new OConfigurationException("Error on opening database: parameter has no value. Syntax is: " + URL_SYNTAX
                + ". URL was: " + iURL);
          parameters.put(kv[0], kv[1]);
        }
      } else
        dbPath = iURL;

      final String dbName = registerDatabaseByPath ? dbPath : OIOUtils.getRelativePathIfAny(dbPath, null);

      OStorage storage;
      if (engine.isShared()) {
        // SEARCH IF ALREADY USED
        storage = storages.get(dbName);
        if (storage == null) {
          // NOT FOUND: CREATE IT
          storage = engine.createStorage(dbPath, parameters);

          final OStorage oldStorage = storages.putIfAbsent(dbName, storage);
          if (oldStorage != null)
            storage = oldStorage;
        }
      } else {
        // REGISTER IT WITH A SERIAL NAME TO AVOID BEING REUSED
        storage = engine.createStorage(dbPath, parameters);
        storages.put(dbName + "__" + serialId.incrementAndGet(), storage);
      }

      for (OOrientListener l : browseListeners())
        l.onStorageRegistered(storage);

      return storage;
    } finally {
      engineLock.readLock().unlock();
    }
  }

  public OStorage registerStorage(OStorage storage) throws IOException {
    engineLock.readLock().lock();
    try {
      for (OOrientListener l : browseListeners())
        l.onStorageRegistered(storage);

      OStorage oldStorage = storages.putIfAbsent(storage.getName(), storage);
      if (oldStorage != null)
        storage = oldStorage;

      return storage;
    } finally {
      engineLock.readLock().unlock();
    }
  }

  public OStorage getStorage(final String dbName) {
    engineLock.readLock().lock();
    try {
      return storages.get(dbName);
    } finally {
      engineLock.readLock().unlock();
    }
  }

  public void registerEngine(final OEngine iEngine) {
    engineLock.readLock().lock();
    try {
      engines.put(iEngine.getName(), iEngine);
    } finally {
      engineLock.readLock().unlock();
    }
  }

  /**
   * Returns the engine by its name.
   *
   * @param engineName
   *          Engine name to retrieve
   * @return OEngine instance of found, otherwise null
   */
  public OEngine getEngine(final String engineName) {
    engineLock.readLock().lock();
    try {
      return engines.get(engineName);
    } finally {
      engineLock.readLock().unlock();
    }
  }

  public Set<String> getEngines() {
    engineLock.readLock().lock();
    try {
      return Collections.unmodifiableSet(engines.keySet());
    } finally {
      engineLock.readLock().unlock();
    }
  }

  public void unregisterStorageByName(final String name) {
    final String dbName = registerDatabaseByPath ? name : OIOUtils.getRelativePathIfAny(name, null);
    final OStorage stg = storages.get(dbName);
    unregisterStorage(stg);
  }

  public void unregisterStorage(final OStorage storage) {
    if (!active)
      // SHUTDOWNING OR NOT ACTIVE: RETURN
      return;

    if (storage == null)
      return;

    engineLock.writeLock().lock();
    try {
      // UNREGISTER ALL THE LISTENER ONE BY ONE AVOIDING SELF-RECURSION BY REMOVING FROM THE LIST
      final Iterable<OOrientListener> listenerCopy = getListenersCopy();
      for (Iterator<OOrientListener> it = listenerCopy.iterator(); it.hasNext();) {
        final OOrientListener l = it.next();
        unregisterListener(l);
        l.onStorageUnregistered(storage);
      }

      final List<String> storagesToRemove = new ArrayList<String>();

      for (Entry<String, OStorage> s : storages.entrySet()) {
        if (s.getValue().equals(storage))
          storagesToRemove.add(s.getKey());
      }

      for (String dbName : storagesToRemove)
        storages.remove(dbName);

    } finally {
      engineLock.writeLock().unlock();
    }
  }

  public Collection<OStorage> getStorages() {
    engineLock.readLock().lock();
    try {
      return new ArrayList<OStorage>(storages.values());
    } finally {
      engineLock.readLock().unlock();
    }
  }

  public Timer getTimer() {
    return timer;
  }

  public void removeShutdownHook() {
    if (shutdownHook != null)
      Runtime.getRuntime().removeShutdownHook(shutdownHook);
  }

  public Iterator<ODatabaseLifecycleListener> getDbLifecycleListeners() {
    return dbLifecycleListeners.keySet().iterator();
  }

  public void addDbLifecycleListener(final ODatabaseLifecycleListener iListener) {
    final Map<ODatabaseLifecycleListener, ODatabaseLifecycleListener.PRIORITY> tmp = new LinkedHashMap<ODatabaseLifecycleListener, ODatabaseLifecycleListener.PRIORITY>(
        dbLifecycleListeners);
    tmp.put(iListener, iListener.getPriority());
    dbLifecycleListeners.clear();
    for (ODatabaseLifecycleListener.PRIORITY p : ODatabaseLifecycleListener.PRIORITY.values()) {
      for (Map.Entry<ODatabaseLifecycleListener, ODatabaseLifecycleListener.PRIORITY> e : tmp.entrySet()) {
        if (e.getValue() == p)
          dbLifecycleListeners.put(e.getKey(), e.getValue());
      }
    }
  }

  public void removeDbLifecycleListener(final ODatabaseLifecycleListener iListener) {
    dbLifecycleListeners.remove(iListener);
  }

  public ThreadGroup getThreadGroup() {
    return threadGroup;
  }

  public ODatabaseThreadLocalFactory getDatabaseThreadFactory() {
    return databaseThreadFactory;
  }

  public ORecordFactoryManager getRecordFactoryManager() {
    return recordFactoryManager;
  }

  public void setRecordFactoryManager(final ORecordFactoryManager iRecordFactoryManager) {
    recordFactoryManager = iRecordFactoryManager;
  }

  public ODatabaseFactory getDatabaseFactory() {
    return databaseFactory;
  }

  public OProfilerMBean getProfiler() {
    return profiler;
  }

  public void setProfiler(final OProfilerMBean iProfiler) {
    profiler = iProfiler;
  }

  public void registerThreadDatabaseFactory(final ODatabaseThreadLocalFactory iDatabaseFactory) {
    databaseThreadFactory = iDatabaseFactory;
  }

  public OScriptManager getScriptManager() {
    return scriptManager;
  }

  private void registerEngine(final String iClassName) {
    try {
      final Class<?> cls = Class.forName(iClassName);
      registerEngine((OEngine) cls.newInstance());
    } catch (Exception e) {
    }
  }
}
TOP

Related Classes of com.orientechnologies.orient.core.Orient

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.