/**
   * Method to find an object value generator based on its name. Caches the generators once
   * generated.
   *
   * @param ec ExecutionContext
   * @param genName The generator name
   * @return The value generator (if any)
   * @throws NucleusException if no generator of that name is found
   */
  protected static ObjectValueGenerator getObjectValueGenerator(
      ExecutionContext ec, String genName) {
    if (!objectValGenerators.isEmpty()) {
      ObjectValueGenerator valGen = objectValGenerators.get(genName);
      if (valGen != null) {
        return valGen;
      }
    }

    try {
      ObjectValueGenerator valGen =
          (ObjectValueGenerator)
              ec.getNucleusContext()
                  .getPluginManager()
                  .createExecutableExtension(
                      "org.datanucleus.store_objectvaluegenerator",
                      new String[] {"name"},
                      new String[] {genName},
                      "class-name",
                      null,
                      null);
      objectValGenerators.put(genName, valGen);
      return valGen;
    } catch (Exception e) {
      NucleusLogger.VALUEGENERATION.info(
          "Exception thrown generating value using objectvaluegenerator " + genName, e);
      throw new NucleusException("Exception thrown generating value for object", e);
    }
  }
  /* (non-Javadoc)
   * @see org.datanucleus.store.valuegenerator.AbstractGenerator#reserveBlock(long)
   */
  protected synchronized ValueGenerationBlock<Long> reserveBlock(long size) {
    if (size < 1) {
      return null;
    }

    if (this.table == null) {
      this.initialiseTable();
    }

    // Allocate value(s)
    long number;
    List<Long> oids = new ArrayList<Long>();
    try {
      number =
          table.incrementColumnValue(
              Bytes.toBytes(key),
              Bytes.toBytes(INCREMENT_COL_NAME),
              Bytes.toBytes(INCREMENT_COL_NAME),
              size);
      long nextNumber = number - size + 1;
      for (int i = 0; i < size; i++) {
        oids.add(nextNumber++);
      }
    } catch (IOException ex) {
      NucleusLogger.VALUEGENERATION.error(
          "IncrementGenerator: Error incrementing generated value", ex);
      throw new NucleusDataStoreException("Error incrementing generated value.", ex);
    }
    return new ValueGenerationBlock<Long>(oids);
  }
  private synchronized void initialiseTable() {
    if (this.table == null) {
      try {
        HBaseStoreManager hbaseMgr = (HBaseStoreManager) storeMgr;
        Configuration config = hbaseMgr.getHbaseConfig();
        HBaseAdmin admin = new HBaseAdmin(config);
        try {
          if (!admin.tableExists(this.tableName)) {
            if (!storeMgr.getSchemaHandler().isAutoCreateTables()) {
              throw new NucleusUserException(Localiser.msg("040011", tableName));
            }

            NucleusLogger.VALUEGENERATION.debug(
                "IncrementGenerator: Creating Table '" + this.tableName + "'");
            HTableDescriptor ht = new HTableDescriptor(this.tableName);
            HColumnDescriptor hcd = new HColumnDescriptor(INCREMENT_COL_NAME);
            hcd.setCompressionType(Algorithm.NONE);
            hcd.setMaxVersions(1);
            ht.addFamily(hcd);
            admin.createTable(ht);
          }
        } finally {
          admin.close();
        }

        this.table = new HTable(config, this.tableName);
        if (!this.table.exists(new Get(Bytes.toBytes(key)))) {
          long initialValue = 0;
          if (properties.containsKey("key-initial-value")) {
            initialValue = Long.valueOf(properties.getProperty("key-initial-value")) - 1;
          }
          this.table.put(
              new Put(Bytes.toBytes(key))
                  .add(
                      Bytes.toBytes(INCREMENT_COL_NAME),
                      Bytes.toBytes(INCREMENT_COL_NAME),
                      Bytes.toBytes(initialValue)));
        }
      } catch (IOException ex) {
        NucleusLogger.VALUEGENERATION.fatal("Error instantiating IncrementGenerator", ex);
      }
    }
  }
Ejemplo n.º 4
0
  /**
   * Method to reserve a block of "size" identities.
   *
   * @param size Block size
   * @return The reserved block
   */
  public ValueGenerationBlock reserveBlock(long size) {
    if (size < 1) {
      return null;
    }

    // search for an ID in the database
    List oid = new ArrayList();
    try {
      if (sequenceTable == null) {
        initialiseSequenceTable();
      }

      DatastoreIdentifier sourceTableIdentifier = null;
      if (properties.getProperty("table-name") != null) {
        sourceTableIdentifier =
            ((RDBMSStoreManager) storeMgr)
                .getIdentifierFactory()
                .newTableIdentifier(properties.getProperty("table-name"));
        // TODO Apply passed in catalog/schema to this identifier rather than the default for the
        // factory
      }
      Long nextId =
          sequenceTable.getNextVal(
              sequenceName,
              connection,
              (int) size,
              sourceTableIdentifier,
              properties.getProperty("column-name"),
              initialValue);
      for (int i = 0; i < size; i++) {
        oid.add(nextId);
        nextId = Long.valueOf(nextId.longValue() + 1);
      }
      if (NucleusLogger.VALUEGENERATION.isDebugEnabled()) {
        NucleusLogger.VALUEGENERATION.debug(LOCALISER.msg("040004", "" + size));
      }
      return new ValueGenerationBlock(oid);
    } catch (SQLException e) {
      throw new ValueGenerationException(LOCALISER_RDBMS.msg("061001", e.getMessage()));
    }
  }
Ejemplo n.º 5
0
  /**
   * Utility to create the datastore identity column and mapping. This is used in 2 modes. The first
   * is where we have a (primary) class table and we aren't creating the OID mapping as a FK to
   * another class. The second is where we have a (secondary) class table and we are creating the
   * OID mapping as a FK to the primary class. In the second case the refTable will be specified.
   *
   * @param columnMetaData The column MetaData for the datastore id
   * @param refTable Table used as a reference (if any)
   * @param cmd The MetaData for the class
   */
  void addDatastoreId(
      ColumnMetaData columnMetaData, DatastoreClass refTable, AbstractClassMetaData cmd) {
    // Create the mapping, setting its table
    datastoreIDMapping = new DatastoreIdMapping();
    datastoreIDMapping.setTable(this);
    datastoreIDMapping.initialize(storeMgr, cmd.getFullClassName());

    // Create a ColumnMetaData in the container if none is defined
    ColumnMetaData colmd = null;
    if (columnMetaData == null) {
      colmd = new ColumnMetaData();
    } else {
      colmd = columnMetaData;
    }
    if (colmd.getName() == null) {
      // Provide default column naming if none is defined
      if (refTable != null) {
        colmd.setName(
            storeMgr
                .getIdentifierFactory()
                .newColumnIdentifier(
                    refTable.getIdentifier().getName(),
                    this.storeMgr
                        .getNucleusContext()
                        .getTypeManager()
                        .isDefaultEmbeddedType(DatastoreId.class),
                    FieldRole.ROLE_OWNER,
                    false)
                .getName());
      } else {
        colmd.setName(
            storeMgr
                .getIdentifierFactory()
                .newColumnIdentifier(
                    identifier.getName(),
                    this.storeMgr
                        .getNucleusContext()
                        .getTypeManager()
                        .isDefaultEmbeddedType(DatastoreId.class),
                    FieldRole.ROLE_NONE,
                    false)
                .getName());
      }
    }

    // Add the datastore identity column as the PK
    Column idColumn =
        addColumn(
            DatastoreId.class.getName(),
            storeMgr.getIdentifierFactory().newIdentifier(IdentifierType.COLUMN, colmd.getName()),
            datastoreIDMapping,
            colmd);
    idColumn.setPrimaryKey();

    // Set the identity column type based on the IdentityStrategy
    String strategyName = cmd.getIdentityMetaData().getValueStrategy().toString();
    if (cmd.getIdentityMetaData().getValueStrategy().equals(IdentityStrategy.CUSTOM)) {
      strategyName = cmd.getIdentityMetaData().getValueStrategy().getCustomName();
    }
    if (strategyName != null && IdentityStrategy.NATIVE.toString().equals(strategyName)) {
      strategyName = storeMgr.getStrategyForNative(cmd, -1);
    }

    // Check the value generator type being stored
    Class valueGeneratedType = Long.class;
    if (strategyName != null && IdentityStrategy.IDENTITY.toString().equals(strategyName)) {
      valueGeneratedType = dba.getAutoIncrementJavaTypeForType(valueGeneratedType);
      if (valueGeneratedType != Long.class) {
        NucleusLogger.DATASTORE_SCHEMA.debug(
            "Class "
                + cmd.getFullClassName()
                + " uses IDENTITY strategy and rather than using BIGINT "
                + " for the column type, using "
                + valueGeneratedType.getName()
                + " since the datastore requires that");
      }
    }
    try {
      // Create generator so we can find the generated type
      // a). Try as unique generator first
      AbstractGenerator generator =
          (AbstractGenerator)
              storeMgr
                  .getNucleusContext()
                  .getPluginManager()
                  .createExecutableExtension(
                      "org.datanucleus.store_valuegenerator",
                      new String[] {"name", "unique"},
                      new String[] {strategyName, "true"},
                      "class-name",
                      new Class[] {String.class, Properties.class},
                      new Object[] {null, null});
      if (generator == null) {
        // b). Try as datastore-specific generator
        generator =
            (AbstractGenerator)
                storeMgr
                    .getNucleusContext()
                    .getPluginManager()
                    .createExecutableExtension(
                        "org.datanucleus.store_valuegenerator",
                        new String[] {"name", "datastore"},
                        new String[] {strategyName, storeMgr.getStoreManagerKey()},
                        "class-name",
                        new Class[] {String.class, Properties.class},
                        new Object[] {null, null});
      }
      try {
        if (generator != null) {
          ParameterizedType parameterizedType =
              (ParameterizedType) generator.getClass().getGenericSuperclass();
          valueGeneratedType = (Class) parameterizedType.getActualTypeArguments()[0];
          if (valueGeneratedType == null) {
            // Use getStorageClass method if available
            valueGeneratedType =
                (Class) generator.getClass().getMethod("getStorageClass").invoke(null);
          }
        }
      } catch (Exception e) {
      }
    } catch (Exception e) {
      NucleusLogger.VALUEGENERATION.warn(
          "Error obtaining generator for strategy=" + strategyName, e);
    }

    storeMgr
        .getMappingManager()
        .createDatastoreMapping(datastoreIDMapping, idColumn, valueGeneratedType.getName());
    logMapping("DATASTORE_ID", datastoreIDMapping);

    // Handle any auto-increment requirement
    if (isObjectIdDatastoreAttributed()) {
      if (this instanceof DatastoreClass && ((DatastoreClass) this).isBaseDatastoreClass()) {
        // Only the base class can be autoincremented
        idColumn.setIdentity(true);
      }
    }

    // Check if auto-increment and that it is supported by this RDBMS
    if (idColumn.isIdentity() && !dba.supportsOption(DatastoreAdapter.IDENTITY_COLUMNS)) {
      throw new NucleusException(
              Localiser.msg("057020", cmd.getFullClassName(), "datastore-identity"))
          .setFatal();
    }
  }