Package com.google.k2crypto.storage

Source Code of com.google.k2crypto.storage.InstalledDriver

/*
* Copyright 2014 Google. Inc.
*
* 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.
*/

package com.google.k2crypto.storage;

import com.google.k2crypto.K2Context;
import com.google.k2crypto.storage.driver.Driver;
import com.google.k2crypto.storage.driver.DriverInfo;
import com.google.k2crypto.storage.driver.ReadableDriver;
import com.google.k2crypto.storage.driver.WrappingDriver;
import com.google.k2crypto.storage.driver.WritableDriver;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.regex.Pattern;

/**
* A driver that has been installed into the storage system.
*
* <p>This class is thread-safe.
*
* @author darylseah@gmail.com (Daryl Seah)
*/
public class InstalledDriver {
 
  // Regex matching a valid URI scheme.
  // (Same as http://tools.ietf.org/html/rfc3986#section-3.1,
  //  except we do not accept upper-case.)
  private static final Pattern LEGAL_ID =
      Pattern.compile("^[a-z][a-z0-9\\+\\-\\.]*$");
 
  // Context for the current K2 session
  private final K2Context context;
 
  // Class of the driver implementation.
  private final Class<? extends Driver> driverClass;
 
  // Constructor obtained from the driver class
  private final Constructor<? extends Driver> constructor;
 
  // Info annotation obtained from the driver class
  private final DriverInfo info;

  // Driver capabilities, derived from the interfaces implemented
  private final boolean canRead;
  private final boolean canWrite;
  private final boolean wrapSupported;
 
  /**
   * Constructs an installed driver from a class and verifies that it conforms
   * to the expected structure.
   *
   * @param context Context for the K2 session.
   * @param driverClass Class of the driver implementation to install.
   *
   * @throws StorageDriverException if the driver does not conform.
   */
  InstalledDriver(K2Context context, Class<? extends Driver> driverClass)
      throws StorageDriverException {
    if (context == null) {
      throw new NullPointerException("context");
    } else if (driverClass == null) {
      throw new NullPointerException("driverClass");
    }
   
    this.context = context;
    this.driverClass = driverClass;
   
    // Determine what the driver can do
    this.canRead = ReadableDriver.class.isAssignableFrom(driverClass);
    this.canWrite = WritableDriver.class.isAssignableFrom(driverClass);
    this.wrapSupported = WrappingDriver.class.isAssignableFrom(driverClass);
   
    if (!canRead && !canWrite) {
      // A driver that can neither read nor write is literally useless
      throw new StorageDriverException(
          driverClass, StorageDriverException.Reason.USELESS);     
    }

    try {
      // Check for a constructor with no arguments
      constructor = driverClass.getDeclaredConstructor();
      // Constructor can only throw Errors or RuntimeExceptions
      for (Class<?> exClass : constructor.getExceptionTypes()) {
        if (!RuntimeException.class.isAssignableFrom(exClass)
            && !Error.class.isAssignableFrom(exClass)) {
          throw new StorageDriverException(
              driverClass, StorageDriverException.Reason.ILLEGAL_THROWS);
        }
      }
      // Try to instantiate the driver (should work if driver is accessible)
      constructor.newInstance();
     
    } catch (NoSuchMethodException ex) {
      // Constructor not found
      throw new StorageDriverException(
          driverClass, StorageDriverException.Reason.NO_CONSTRUCTOR);       
    } catch (ReflectiveOperationException ex) {
      // Instantiation failed
      throw new StorageDriverException(
          driverClass, StorageDriverException.Reason.INSTANTIATE_FAIL);
    }

    // Check that annotation is present
    info = driverClass.getAnnotation(DriverInfo.class);
    if (info == null) {
      throw new StorageDriverException(
          driverClass, StorageDriverException.Reason.NO_METADATA);
    }
   
    // Check that driver identifier is legal
    if (!LEGAL_ID.matcher(info.id()).matches()) {
      throw new StorageDriverException(
          driverClass, StorageDriverException.Reason.ILLEGAL_ID);       
    }
  }
 
  /**
   * Instantiates a new store (driver) from the driver installation.
   */
  Driver instantiate() {
    try {
      // Use reflection to instantiate the driver
      Driver driver = constructor.newInstance();
      driver.initialize(context);
      return driver;
    } catch (InvocationTargetException ex) {
      Throwable t = ex.getCause();
      // Re-throw throwables that do not need an explicit catch. (This should
      // not actually happen unless the driver has a flaky constructor.)
      if (t instanceof Error) {
        throw (Error)t;
      } else if (t instanceof RuntimeException) {
        throw (RuntimeException)t;
      } else {
        // This should not happen, owing to construction-time checks.
        throw new AssertionError("Should not happen!", t);
      }
    } catch (ReflectiveOperationException ex) {
      // Should not happen because we test instantiate in the constructor...
      throw new AssertionError("Should not happen!", ex);
    }
  }
 
  /**
   * Returns the context used when the driver was installed.
   */
  K2Context getContext() {
    return context;
  }
 
  /**
   * Returns the driver class.
   */
  public Class<? extends Driver> getDriverClass() {
    return driverClass;
  }
 
  /**
   * Returns the identifier of the driver.
   */
  public String getId() {
    return info.id();
  }
 
  /**
   * Returns the descriptive name of the driver.
   */
  public String getName() {
    return info.name();
  }
 
  /**
   * Returns the version of the driver.
   */
  public String getVersion() {
    return info.version();
  }
 
  /**
   * Returns {@code true} if the driver can read keys, {@code false} otherwise.
   */
  public boolean canRead() {
    return canRead;
  }
 
  /**
   * Returns whether the driver can only read keys and not write them.
   */
  public boolean isReadOnly() {
    return canRead && !canWrite;
  }
 
  /**
   * Returns {@code true} if the driver can write keys, {@code false} otherwise.
   */
  public boolean canWrite() {
    return canWrite;
  }
 
  /**
   * Returns whether the driver can only write keys and not read them.
   */
  public boolean isWriteOnly() {
    return canWrite && !canRead;
  }
 
  /**
   * Returns whether the driver supports wrapped (encrypted) keys.
   */
  public boolean isWrapSupported() {
    return wrapSupported;
  }
 
  /**
   * Returns the hash-code for the driver, which is the hash of the driver
   * class.
   */
  @Override
  public int hashCode() {
    return driverClass.hashCode();
  }
 
  /**
   * Tests the driver for equality with an object.
   *
   * @param obj Object to compare to.
   *
   * @return {@code true} if, and only if, the object is also an
   *         InstalledDriver and it has the same driver class and context as
   *         this one.
   */
  @Override
  public boolean equals(Object obj) {
    if (obj instanceof InstalledDriver) {
      InstalledDriver other = (InstalledDriver)obj;
      return other.driverClass.equals(driverClass)
          && other.context.equals(context);
    }
    return false;
  }
 
  /**
   * @see Object#toString()
   */
  @Override
  public String toString() {
    return "[" + getId() + "/" + driverClass.getName() + "] "
        + getName() + " " + getVersion();
  }
}
TOP

Related Classes of com.google.k2crypto.storage.InstalledDriver

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.