All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.orientechnologies.orient.console.OConsoleDatabaseApp Maven / Gradle / Ivy

There is a newer version: 3.2.41
Show newest version
/*
 *
 *  *  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.console;

import com.orientechnologies.common.collection.OMultiValue;
import com.orientechnologies.common.console.TTYConsoleReader;
import com.orientechnologies.common.console.annotation.ConsoleCommand;
import com.orientechnologies.common.console.annotation.ConsoleParameter;
import com.orientechnologies.common.exception.OSystemException;
import com.orientechnologies.common.io.OFileUtils;
import com.orientechnologies.common.io.OIOException;
import com.orientechnologies.common.listener.OProgressListener;
import com.orientechnologies.common.log.OLogManager;
import com.orientechnologies.orient.client.remote.OEngineRemote;
import com.orientechnologies.orient.client.remote.OServerAdmin;
import com.orientechnologies.orient.client.remote.OStorageRemote;
import com.orientechnologies.orient.core.OConstants;
import com.orientechnologies.orient.core.OSignalHandler;
import com.orientechnologies.orient.core.Orient;
import com.orientechnologies.orient.core.command.OCommandOutputListener;
import com.orientechnologies.orient.core.command.script.OCommandExecutorScript;
import com.orientechnologies.orient.core.command.script.OCommandScript;
import com.orientechnologies.orient.core.config.OGlobalConfiguration;
import com.orientechnologies.orient.core.config.OStorageConfiguration;
import com.orientechnologies.orient.core.config.OStorageEntryConfiguration;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.db.record.ridbag.ORidBag;
import com.orientechnologies.orient.core.db.tool.*;
import com.orientechnologies.orient.core.exception.OConfigurationException;
import com.orientechnologies.orient.core.exception.ODatabaseException;
import com.orientechnologies.orient.core.exception.ORetryQueryException;
import com.orientechnologies.orient.core.id.ORecordId;
import com.orientechnologies.orient.core.index.OIndex;
import com.orientechnologies.orient.core.index.OIndexDefinition;
import com.orientechnologies.orient.core.intent.OIntentMassiveInsert;
import com.orientechnologies.orient.core.intent.OIntentMassiveRead;
import com.orientechnologies.orient.core.iterator.OIdentifiableIterator;
import com.orientechnologies.orient.core.iterator.ORecordIteratorCluster;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.metadata.schema.OProperty;
import com.orientechnologies.orient.core.metadata.security.OUser;
import com.orientechnologies.orient.core.record.ORecord;
import com.orientechnologies.orient.core.record.impl.OBlob;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.security.OSecurityManager;
import com.orientechnologies.orient.core.serialization.OBase64Utils;
import com.orientechnologies.orient.core.serialization.serializer.OStringSerializerHelper;
import com.orientechnologies.orient.core.serialization.serializer.record.ORecordSerializer;
import com.orientechnologies.orient.core.serialization.serializer.record.ORecordSerializerFactory;
import com.orientechnologies.orient.core.serialization.serializer.record.binary.ORecordSerializationDebug;
import com.orientechnologies.orient.core.serialization.serializer.record.binary.ORecordSerializationDebugProperty;
import com.orientechnologies.orient.core.serialization.serializer.record.binary.ORecordSerializerBinaryDebug;
import com.orientechnologies.orient.core.serialization.serializer.record.string.ORecordSerializerStringAbstract;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.orientechnologies.orient.core.sql.filter.OSQLPredicate;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;
import com.orientechnologies.orient.core.storage.OCluster;
import com.orientechnologies.orient.core.storage.ORawBuffer;
import com.orientechnologies.orient.core.storage.OStorage;
import com.orientechnologies.orient.core.storage.OStorageProxy;
import com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage;
import com.orientechnologies.orient.core.storage.impl.local.paginated.OClusterPageDebug;
import com.orientechnologies.orient.core.storage.impl.local.paginated.OLocalPaginatedStorage;
import com.orientechnologies.orient.core.storage.impl.local.paginated.OPaginatedCluster;
import com.orientechnologies.orient.core.storage.impl.local.paginated.OPaginatedClusterDebug;
import com.orientechnologies.orient.server.config.OServerConfigurationManager;
import com.orientechnologies.orient.server.config.OServerUserConfiguration;
import sun.misc.Signal;
import sun.misc.SignalHandler;

import java.io.*;
import java.lang.reflect.Array;
import java.util.*;
import java.util.Map.Entry;

public class OConsoleDatabaseApp extends OrientConsole implements OCommandOutputListener, OProgressListener {
  protected static final int DEFAULT_WIDTH = 150;

  protected ODatabaseDocumentTx currentDatabase;
  protected String              currentDatabaseName;
  protected ORecord             currentRecord;
  protected int                 currentRecordIdx;
  protected List currentResultSet;
  protected Object              currentResult;
  protected OServerAdmin        serverAdmin;
  private int windowSize = DEFAULT_WIDTH;
  private int    lastPercentStep;
  private String currentDatabaseUserName;
  private String currentDatabaseUserPassword;
  private int maxMultiValueEntries = 10;

  public OConsoleDatabaseApp(final String[] args) {
    super(args);
  }

  public static void main(final String[] args) {
    int result = 0;

    try {
      boolean tty = false;
      try {
        if (setTerminalToCBreak())
          tty = true;

        Runtime.getRuntime().addShutdownHook(new Thread() {
          @Override
          public void run() {
            restoreTerminal();
          }
        });

      } catch (Exception ignored) {
      }

      new OSignalHandler().installDefaultSignals(new SignalHandler() {

        public void handle(Signal signal) {
          restoreTerminal();
        }
      });

      final OConsoleDatabaseApp console = new OConsoleDatabaseApp(args);
      if (tty)
        console.setReader(new TTYConsoleReader());

      result = console.run();

    } finally {
      restoreTerminal();
    }

    Orient.instance().shutdown();
    System.exit(result);
  }

  protected static void restoreTerminal() {
    try {
      stty("echo");
    } catch (Exception ignored) {
    }
  }

  protected static boolean setTerminalToCBreak() throws IOException, InterruptedException {
    // set the console to be character-buffered instead of line-buffered
    int result = stty("-icanon min 1");
    if (result != 0) {
      return false;
    }

    // disable character echoing
    stty("-echo");
    return true;
  }

  /**
   * Execute the stty command with the specified arguments against the current active terminal.
   */
  protected static int stty(final String args) throws IOException, InterruptedException {
    String cmd = "stty " + args + " < /dev/tty";

    return exec(new String[] { "sh", "-c", cmd });
  }

  /**
   * Execute the specified command and return the output (both stdout and stderr).
   */
  protected static int exec(final String[] cmd) throws IOException, InterruptedException {
    ByteArrayOutputStream bout = new ByteArrayOutputStream();

    Process p = Runtime.getRuntime().exec(cmd);
    int c;
    InputStream in = p.getInputStream();

    while ((c = in.read()) != -1) {
      bout.write(c);
    }

    in = p.getErrorStream();

    while ((c = in.read()) != -1) {
      bout.write(c);
    }

    p.waitFor();

    return p.exitValue();
  }

  @ConsoleCommand(aliases = {
      "use database" }, description = "Connect to a database or a remote Server instance", onlineHelp = "Console-Command-Connect")
  public void connect(
      @ConsoleParameter(name = "url", description = "The url of the remote server or the database to connect to in the format ':'") String iURL,
      @ConsoleParameter(name = "user", description = "User name") String iUserName,
      @ConsoleParameter(name = "password", description = "User password", optional = true) String iUserPassword)
      throws IOException {
    disconnect();

    if (iUserPassword == null) {
      message("Enter password: ");
      final BufferedReader br = new BufferedReader(new InputStreamReader(this.in));
      iUserPassword = br.readLine();
      message("\n");
    }

    currentDatabaseUserName = iUserName;
    currentDatabaseUserPassword = iUserPassword;

    if (iURL.contains("/")) {
      // OPEN DB
      message("\nConnecting to database [" + iURL + "] with user '" + iUserName + "'...");

      currentDatabase = new ODatabaseDocumentTx(iURL);

      currentDatabase.registerListener(new OConsoleDatabaseListener(this));
      currentDatabase.open(iUserName, iUserPassword);
      currentDatabaseName = currentDatabase.getName();
    } else {
      // CONNECT TO REMOTE SERVER
      message("\nConnecting to remote Server instance [" + iURL + "] with user '" + iUserName + "'...");

      serverAdmin = new OServerAdmin(iURL).connect(iUserName, iUserPassword);
      currentDatabase = null;
      currentDatabaseName = null;
    }

    message("OK");

    final ODocument distribCfg = getDistributedConfiguration();
    if (distribCfg != null)
      listServers();
  }

  @ConsoleCommand(aliases = {
      "close database" }, description = "Disconnect from the current database", onlineHelp = "Console-Command-Disconnect")
  public void disconnect() {
    if (serverAdmin != null) {
      message("\nDisconnecting from remote server [" + serverAdmin.getURL() + "]...");
      serverAdmin.close(true);
      serverAdmin = null;
      message("\nOK");
    }

    if (currentDatabase != null) {
      message("\nDisconnecting from the database [" + currentDatabaseName + "]...");

      final OStorage stg = Orient.instance().getStorage(currentDatabase.getURL());

      currentDatabase.activateOnCurrentThread();
      if (!currentDatabase.isClosed())
        currentDatabase.close();

      // FORCE CLOSING OF STORAGE: THIS CLEAN UP REMOTE CONNECTIONS
      if (stg != null)
        stg.close(true, false);

      currentDatabase = null;
      currentDatabaseName = null;
      currentRecord = null;

      message("OK");
    }
  }

  @ConsoleCommand(description = "Create a new database. For encrypted database or portion of database, set the variable 'storage.encryptionKey' with the key to use", onlineHelp = "Console-Command-Create-Database")
  public void createDatabase(
      @ConsoleParameter(name = "database-url", description = "The url of the database to create in the format ':'") String databaseURL,
      @ConsoleParameter(name = "user", optional = true, description = "Server administrator name") String userName,
      @ConsoleParameter(name = "password", optional = true, description = "Server administrator password") String userPassword,
      @ConsoleParameter(name = "storage-type", optional = true, description = "The type of the storage: 'plocal' for disk-based databases and 'memory' for in-memory database") String storageType,
      @ConsoleParameter(name = "db-type", optional = true, description = "The type of the database used between 'document' and 'graph'. By default is graph.") String databaseType,
      @ConsoleParameter(name = "[options]", optional = true, description = "Additional options, example: -encryption=aes -compression=snappy") final String options)
      throws IOException {

    if (userName == null)
      userName = OUser.ADMIN;
    if (userPassword == null)
      userPassword = OUser.ADMIN;
    if (storageType == null) {
      if (databaseURL.startsWith(OEngineRemote.NAME + ":"))
        throw new IllegalArgumentException("Missing storage type for remote database");

      int pos = databaseURL.indexOf(":");
      if (pos == -1)
        throw new IllegalArgumentException("Invalid URL");
      storageType = databaseURL.substring(0, pos);
    }
    if (databaseType == null)
      databaseType = "graph";

    message("\nCreating database [" + databaseURL + "] using the storage type [" + storageType + "]...");

    currentDatabaseUserName = userName;
    currentDatabaseUserPassword = userPassword;

    final Map omap = new HashMap();

    if (options != null) {
      final List kvOptions = OStringSerializerHelper.smartSplit(options, ',', false);
      for (String option : kvOptions) {
        final String[] values = option.split("=");
        if (values.length != 2)
          throw new IllegalArgumentException("Options must have in th format -