Source: errors.js

/*-
 *
 *  This file is part of Oracle NoSQL Database
 *  Copyright (C) 2011, 2015 Oracle and/or its affiliates.  All rights reserved.
 *
 * If you have received this file as part of Oracle NoSQL Database the
 * following applies to the work as a whole:
 *
 *   Oracle NoSQL Database server software is free software: you can
 *   redistribute it and/or modify it under the terms of the GNU Affero
 *   General Public License as published by the Free Software Foundation,
 *   version 3.
 *
 *   Oracle NoSQL Database is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Affero General Public License for more message.
 *
 * If you have received this file as part of Oracle NoSQL Database Client or
 * distributed separately the following applies:
 *
 *   Oracle NoSQL Database client software is free software: you can
 *   redistribute it and/or modify it under the terms of the Apache License
 *   as published by the Apache Software Foundation, version 2.0.
 *
 * You should have received a copy of the GNU Affero General Public License
 * and/or the Apache License in the LICENSE file along with Oracle NoSQL
 * Database client or server distribution.  If not, see
 * <http://www.gnu.org/licenses/>
 * or
 * <http://www.apache.org/licenses/LICENSE-2.0>.
 *
 * An active Oracle commercial licensing agreement for this product supersedes
 * these licenses and in such case the license notices, but not the copyright
 * notice, may be removed by you in connection with your distribution that is
 * in accordance with the commercial licensing terms.
 *
 * For more information please contact:
 *
 * berkeleydb-info_us@oracle.com
 *
 */
'use strict';

/*global Logger*/

var ttypes = require('./thrift/ondb_types');

/**
 * Generic Error for NoSQL DB Node Client.
 * @constructor
 *
 * @param {Object} message The error message to be included on the object.
 */
function NoSQLDBError(message) {
  Logger.error('NoSQL Error: ' + message);
  Error.call(this, message);
  Error.captureStackTrace(this, NoSQLDBError);
  this.name = 'NoSQLDB-Error';
  this.message = message;
}
util.inherits(NoSQLDBError, Error);
exports.NoSQLDBError = NoSQLDBError;

/**
 * Parameter Error
 * @constructor
 *
 * @param {String} parameter The parameter name.
 * @param {String} extraInfo Additional information about the error.
 */
function ParameterError(parameter, extraInfo) {
  Logger.error('Parameter error: ' + parameter + ' - ' + extraInfo);
  Error.call(this, parameter);
  Error.captureStackTrace(this, ParameterError);
  this.name = 'NoSQLDB-ParameterError';
  this.message = 'The parameter ' + parameter +
  ' is missing or incorrect.'
  if (extraInfo)
    this.message += '\n Extended info: ' + extraInfo;
}
util.inherits(ParameterError, Error);
exports.ParameterError = ParameterError;

function missingParameter(parameter, parameterName, type) {
  if (type)
    if (typeof parameter !== type) {
      var message = parameterName + ' is not of the type ' + type;
      var error = new Errors.ParameterError(parameterName, message);
      Logger.error(error);
      throw error;
    }

  if ((parameter === null) || (parameter === undefined)) {
    var message =
      (parameter === undefined ? 'Missing' : 'Undefined' ) + ' parameter';
    var error = new Errors.ParameterError(parameterName, message);
    Logger.error(error);
    throw error;
  }
}
exports.missingParameter = missingParameter;

/**
 * Connection Error
 * @constructor
 *
 * @param {Object} message The error message to be included on the object.
 * Connection error.
 */
function ConnectionError(message, extraInfo) {
  Logger.error('Connection error: ' + message + ' - ' + extraInfo);
  Error.call(this, message);
  Error.captureStackTrace(this, ConnectionError);
  this.name = 'NoSQLDB-ConnectionError';
  this.message = 'Error with NoSQL DB Connection: ' + message;
  if (extraInfo)
    this.message += '\n' + extraInfo;
}
util.inherits(ConnectionError, Error);
exports.ConnectionError = ConnectionError;

/**
 * Store Error
 * @constructor
 *
 * @param {Object} message The error message to be included on the object.
 * @param {String} extraInfo Additional information about the error.
 * Connection error.
 */
function StoreError(message, extraInfo) {
  Logger.error('Store error: ' + message + ' - ' + extraInfo);
  Error.call(this, message);
  Error.captureStackTrace(this, StoreError);
  this.name = 'NoSQLDB-StoreError';
  this.message = message;
  if (extraInfo)
    this.message += '\n' + extraInfo;
}
util.inherits(StoreError, Error);
exports.StoreError = StoreError;

/**
 * Iterator Error
 * @constructor
 *
 * @param {Object} message The error message to be included on the object.
 */
function IteratorError(message) {
  Logger.error('Iterator error: ' + message);
  Error.call(this, message);
  Error.captureStackTrace(this, IteratorError);
  this.name = 'NoSQLDB-IteratorError';
  this.message = message;
}
util.inherits(IteratorError, Error);
exports.IteratorError = IteratorError;

exports.equal = function (/*Error*/ error, /*String*/ errorMessage) {
  return (error instanceof Error) && (error.message === errorMessage)
};


function getProxyError(error, method) {
  Logger.error('Capturing proxy error: ' + error);
  var result = null;
  if (error instanceof ttypes.TDurabilityException)
    result = new DurabilityException(error);
  else if (error instanceof ttypes.TRequestTimeoutException)
    result = new RequestTimeoutException(error);
  else if (error instanceof ttypes.TFaultException)
    result = new FaultException(error);
  else if (error instanceof ttypes.TConsistencyException)
    result = new ConsistencyException(error);
  else if (error instanceof ttypes.TIllegalArgumentException)
    result = new IllegalArgumentException(error);
  else if (error instanceof ttypes.TIteratorTimeoutException)
    result = new IteratorTimeoutException(error);
  else if (error instanceof ttypes.TUnverifiedConnectionException)
    result = new UnverifiedConnectionException(error);
  else if (error instanceof ttypes.TProxyException)
    result = new ProxyException(error);
  else if (error instanceof ttypes.TCancellationException)
    result = new CancellationException(error);
  else if (error instanceof ttypes.TExecutionException)
    result = new ExecutionException(error);
  else if (error instanceof ttypes.TInterruptedException)
    result = new InterruptedException(error);
  else if (error instanceof ttypes.TTimeoutException)
    result = new TimeoutException(error);
  else if (error instanceof ttypes.TTableOpExecutionException)
    result = new TableOpExecutionException(error);
  else if (error instanceof ttypes.TRequestLimitException)
    result = new RequestLimitException(error);
  else if (error instanceof ttypes.TAuthenticationFailureException)
    result = new AuthenticationFailureException(error);
  else if (error instanceof ttypes.TAuthenticationRequiredException)
    result = new AuthenticationRequiredException(error);
  else if (error instanceof ttypes.TUnauthorizedException)
    result = new UnauthorizedException(error);
  else
    result = new UnknownException(error);

  result.method = method;
  return result;
}
exports.getProxyError = getProxyError;


// Proxy Exceptions
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

/**
 * Returned when write operations cannot be initiated because a quorum of
 * Replicas as determined by the Durability.ReplicaAckPolicy was not available.
 * The likelihood of this exception being thrown depends on the number of nodes
 * per replication group, the rate of node failures and how quickly a failed
 * node is restored to operation, and the specified ReplicaAckPolicy. The
 * ReplicaAckPolicy for the default durability policy is
 * Durability.ReplicaAckPolicy.SIMPLE_MAJORITY. With SIMPLE_MAJORITY,
 * this exception is thrown only when the majority of nodes in a replication
 * group are unavailable, and in a well-maintained KVStore system with at least
 * three nodes per replication group this exception should rarely be thrown.
 * If the client overrides the default and specifies
 * Durability.ReplicaAckPolicy.ALL, then this exception will be thrown when any
 * node in a replication group is unavailable; in other words, it is much more
 * likely to be thrown. If the client specifies
 * Durability.ReplicaAckPolicy.NONE, then this exception will never be thrown.
 * When this exception is thrown the KVStore service will perform administrative
 * notifications so that actions can be taken to correct the problem. Depending
 * on the nature of the application, the client may wish to:
 * - retry the write operation immediately,
 * - fall back to a read-only mode and resume write operations at a later time,
 * or
 * - give up and report an error at a higher level.
 */
function DurabilityException(args) {
  Error.call(this);
  Error.captureStackTrace(this, DurabilityException);
  this.name = 'DurabilityException';
  this.availableReplicas = null;
  this.commitPolicy = null;
  this.requiredNodeCount = null;
  this.message = null;
  if (args) {
    if (args.availableReplicas !== undefined) {
      this.availableReplicas = args.availableReplicas;
    }
    if (args.commitPolicy !== undefined) {
      this.commitPolicy = args.commitPolicy;
    }
    if (args.requiredNodeCount !== undefined) {
      this.requiredNodeCount = args.requiredNodeCount;
    }
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(DurabilityException, Error);
exports.DurabilityException = DurabilityException;
/**
 * Returned when a request cannot be processed because the configured timeout
 * interval is exceeded.
 * The default timeout interval is five seconds, and this exception should
 * rarely be thrown.
 * Note that the durability of an update operation is uncertain if it results
 * in a RequestTimeoutException being thrown. The changes requested by the
 * update may or may not have been committed to the master or propagated to one
 * or more replicas. Applications may want to retry the update operation if it
 * is idempotent, or perform read operations to determine the outcome of the
 * previous update.
 * Note also that if the consistency specified for a read operation is
 * Consistency.NONE_REQUIRED_NO_MASTER, then this exception will be thrown
 * if the operation is attempted when the only node available is the Master.
 * Depending on the nature of the application, when this exception is thrown
 * the client may wish to:
 * - retry the operation,
 * - fall back to using a larger timeout interval, and resume using the
 * original timeout interval at a later time, or
 * - give up and report an error at a higher level.
 */
function RequestTimeoutException(args) {
  Error.call(this);
  Error.captureStackTrace(this, RequestTimeoutException);
  this.name = 'RequestTimeoutException';
  this.message = null;
  this.timeoutMs = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
    if (args.timeoutMs !== undefined) {
      this.timeoutMs = args.timeoutMs;
    }
  }
}
util.inherits(RequestTimeoutException, Error);
exports.RequestTimeoutException = RequestTimeoutException;

/**
 * Used to indicate an error condition that cannot normally be handled by the
 * caller of the method, except by retrying the operation.
 * When the error occurred remotely and was due to an internally defined server
 * exception.
 * When the error occurred remotely, it will have already been logged and
 * reported on a remote KVStore node and will be available to administrators.
 * However, to correlate client and server errors and to make error information
 * easily accessible on the client, it is good practice to also log the error
 * locally. Errors that originated locally are not automatically logged and
 * available to administrators, and the client application is responsible for
 * reporting them.
 */
function FaultException(args) {
  Error.call(this);
  Error.captureStackTrace(this, FaultException);
  this.name = 'FaultException';
  this.faultClassName = null;
  this.remoteStackTrace = null;
  this.wasLoggedRemotely = null;
  this.message = null;
  if (args) {
    if (args.faultClassName !== undefined) {
      this.faultClassName = args.faultClassName;
    }
    if (args.remoteStackTrace !== undefined) {
      this.remoteStackTrace = args.remoteStackTrace;
    }
    if (args.wasLoggedRemotely !== undefined) {
      this.wasLoggedRemotely = args.wasLoggedRemotely;
    }
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(FaultException, Error);
exports.FaultException = FaultException;

/**
 * Returned when a single or multiple-operation transaction fails because the
 * specified Consistency could not be met, within the allowed timeout period.
 * The likelihood of this exception being thrown depends on the specified
 * Consistency and the general health of the KVStore system. The default
 * consistency policy is SimpleConsistency.NONE_REQUIRED. With
 * SimpleConsistency.NONE_REQUIRED (the default),
 * SimpleConsistency.NONE_REQUIRED_NO_MASTER, or SimpleConsistency.ABSOLUTE,
 * this exception will never be thrown.
 * If the client overrides the default and specifies a TimeConsistency or
 * VersionConsistency setting, then this exception will be thrown when the
 * specified consistency requirement cannot be satisfied within the timeout
 * period associated with the consistency setting. If this exception is
 * encountered frequently, it indicates that the consistency policy
 * requirements are too strict and cannot be met routinely given the load
 * being placed on the system and the hardware resources that are available
 * to service the load.
 * Depending on the nature of the application, when this exception is thrown
 * the client may wish to
 * - retry the read operation,
 * - fall back to using a larger timeout or a less restrictive consistency
 *  setting (for example, SimpleConsistency.NONE_REQUIRED), and resume using
 *  the original consistency setting at a later time, or
 * - give up and report an error at a higher level.
 */
function ConsistencyException(args) {
  Error.call(this);
  Error.captureStackTrace(this, ConsistencyException);
  this.name = 'ConsistencyException';
  this.consistencyPolicy = null;
  this.message = null;
  if (args) {
    if (args.consistencyPolicy !== undefined) {
      this.consistencyPolicy = args.consistencyPolicy;
    }
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(ConsistencyException, Error);
exports.ConsistencyException = ConsistencyException;

/**
 * Returned when any of the arguments sent to the server is wrong.
 */
function IllegalArgumentException(args) {
  Error.call(this);
  Error.captureStackTrace(this, IllegalArgumentException);
  this.name = 'IllegalArgumentException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(IllegalArgumentException, Error);
exports.IllegalArgumentException = IllegalArgumentException;

function IteratorTimeoutException(args) {
  Error.call(this);
  Error.captureStackTrace(this, IteratorTimeoutException);
  this.name = 'IteratorTimeoutException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(IteratorTimeoutException, Error);
exports.IteratorTimeoutException = IteratorTimeoutException;

function UnverifiedConnectionException(args) {
  Error.call(this);
  Error.captureStackTrace(this, UnverifiedConnectionException);
  this.name = 'UnverifiedConnectionException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(UnverifiedConnectionException, Error);
exports.UnverifiedConnectionException = UnverifiedConnectionException;

function ProxyException(args) {
  Error.call(this);
  Error.captureStackTrace(this, ProxyException);
  this.name = 'TProxyException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(ProxyException, Error);
exports.ProxyException = ProxyException;

function CancellationException(args) {
  Error.call(this);
  Error.captureStackTrace(this, CancellationException);
  this.name = 'CancellationException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(CancellationException, Error);
exports.CancellationException = CancellationException;

function ExecutionException(args) {
  Error.call(this);
  Error.captureStackTrace(this, ExecutionException);
  this.name = 'ExecutionException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(ExecutionException, Error);
exports.ExecutionException = ExecutionException;

function InterruptedException(args) {
  Error.call(this);
  Error.captureStackTrace(this, InterruptedException);
  this.name = 'InterruptedException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(InterruptedException, Error);
exports.InterruptedException = InterruptedException;

function TimeoutException(args) {
  Error.call(this);
  Error.captureStackTrace(this, TimeoutException);
  this.name = 'TimeoutException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(TimeoutException, Error);
exports.TimeoutException = TimeoutException;

/**
 * Used to indicate a failure in executeUpdates.
 **/
function TableOpExecutionException(args) {
  Error.call(this);
  Error.captureStackTrace(this, TableOpExecutionException);
  this.name = 'TableOpExecutionException';
  this.operation = null;
  this.failedOperationIndex = null;
  this.operationResult = null;
  this.message = null;
  if (args) {
    if (args.operation !== undefined) {
      this.operation = args.operation;
    }
    if (args.failedOperationIndex !== undefined) {
      this.failedOperationIndex = args.failedOperationIndex;
    }
    if (args.operationResult !== undefined) {
      this.operationResult = args.operationResult;
    }
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(TableOpExecutionException, Error);
exports.TableOpExecutionException = TableOpExecutionException;

/**
 * Thrown when a request cannot be processed because it would exceed the
 * maximum number of active requests for a node as configured by
 * -request-limit.
 **/
function RequestLimitException(args) {
  Error.call(this);
  Error.captureStackTrace(this, RequestLimitException);
  this.name = 'RequestLimitException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(RequestLimitException, Error);
exports.RequestLimitException = RequestLimitException;

/**
 * This exception is thrown if an application passes invalid credentials to
 * an authentication operation.
 **/
function AuthenticationFailureException(args) {
  Error.call(this);
  Error.captureStackTrace(this, AuthenticationFailureException);
  this.name = 'AuthenticationFailureException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(AuthenticationFailureException, Error);
exports.AuthenticationFailureException = AuthenticationFailureException;

/**
 * This exception is thrown when a secured operation is attempted and the
 * client is not currently authenticated. It can occur if login credentials
 * were specified, but the login session has expired, requiring that the client
 * reauthenticate itself.
 **/
function AuthenticationRequiredException(args) {
  Error.call(this);
  Error.captureStackTrace(this, AuthenticationRequiredException);
  this.name = 'AuthenticationRequiredException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(AuthenticationRequiredException, Error);
exports.AuthenticationRequiredException = AuthenticationRequiredException;

/**
 * This exception is thrown from methods where an authenticated user is
 * attempting to perform an operation for which they are not authorized.
 * An application that receives this exception typically should not retry the
 * operation.
 **/
function UnauthorizedException(args) {
  Error.call(this);
  Error.captureStackTrace(this, UnauthorizedException);
  this.name = 'UnauthorizedException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(UnauthorizedException, Error);
exports.UnauthorizedException = UnauthorizedException;

/**
 * This exception is thrown when a non recognized error is received from the
 * proxy.
 **/
function UnknownException(args) {
  Error.call(this);
  Error.captureStackTrace(this, UnauthorizedException);
  this.name = 'UnknownException';
  this.message = null;
  if (args) {
    if (args.message !== undefined) {
      this.message = args.message;
    }
  }
}
util.inherits(UnknownException, Error);
exports.UnknownException = UnknownException;