예제 #1
0
  /** Initialize the SEQUENCE key generator. */
  public SequenceKeyGenerator(PersistenceFactory factory, Properties params, int sqlType)
      throws MappingException {
    boolean returning;

    _factoryName = factory.getFactoryName();
    returning = "true".equals(params.getProperty("returning"));
    _triggerPresent = "true".equals(params.getProperty("trigger", "false"));

    if (!_factoryName.equals(OracleFactory.FACTORY_NAME)
        && !_factoryName.equals(PostgreSQLFactory.FACTORY_NAME)
        && !_factoryName.equals(InterbaseFactory.FACTORY_NAME)
        && !_factoryName.equals("sapdb")
        && !_factoryName.equals(DB2Factory.FACTORY_NAME)) {
      throw new MappingException(
          Messages.format("mapping.keyGenNotCompatible", getClass().getName(), _factoryName));
    }
    if (!_factoryName.equals(OracleFactory.FACTORY_NAME) && returning) {
      throw new MappingException(
          Messages.format(
              "mapping.keyGenParamNotCompat",
              "returning=\"true\"",
              getClass().getName(),
              _factoryName));
    }
    _factory = factory;
    _seqName = params.getProperty("sequence", "{0}_seq");

    _style =
        (_factoryName.equals(PostgreSQLFactory.FACTORY_NAME)
                || _factoryName.equals(InterbaseFactory.FACTORY_NAME)
                || _factoryName.equals(DB2Factory.FACTORY_NAME)
            ? BEFORE_INSERT
            : (returning ? DURING_INSERT : AFTER_INSERT));
    if (_triggerPresent && !returning) {
      _style = AFTER_INSERT;
    }
    if (_triggerPresent && _style == BEFORE_INSERT)
      throw new MappingException(
          Messages.format(
              "mapping.keyGenParamNotCompat",
              "trigger=\"true\"",
              getClass().getName(),
              _factoryName));

    _sqlType = sqlType;
    supportsSqlType(sqlType);

    try {
      _increment = Integer.parseInt(params.getProperty("increment", "1"));
    } catch (NumberFormatException nfe) {
      _increment = 1;
    }
  }
  protected FieldDescriptorImpl createFieldDesc(final Class javaClass, final FieldMapping fieldMap)
      throws MappingException {

    // If not an SQL field, return a stock field descriptor.
    Sql sql = fieldMap.getSql();
    if (sql == null) {
      return super.createFieldDesc(javaClass, fieldMap);
    }

    String fieldName = fieldMap.getName();

    // If the field type is supplied, grab it and use it to locate the
    // field/accessor.
    Class fieldType = null;
    if (fieldMap.getType() != null) {
      fieldType = resolveType(fieldMap.getType());
    }

    // If the field is declared as a collection, grab the collection type as
    // well and use it to locate the field/accessor.
    CollectionHandler colHandler = null;
    boolean isLazy = fieldMap.getLazy();
    if (fieldMap.getCollection() != null) {
      Class colType = CollectionHandlers.getCollectionType(fieldMap.getCollection().toString());
      colHandler = CollectionHandlers.getHandler(colType);

      if (colType.getName().equals("java.util.Iterator") && isLazy) {
        String err = "Lazy loading not supported for collection type 'iterator'";
        throw new MappingException(err);
      }

      if (colType.getName().equals("java.util.Enumeration") && isLazy) {
        String err = "Lazy loading not supported for collection type 'enumerate'";
        throw new MappingException(err);
      }
    }

    TypeInfo typeInfo = getTypeInfo(fieldType, colHandler, fieldMap);

    ExtendedFieldHandler exfHandler = null;
    FieldHandler handler = null;

    // -- check for user supplied FieldHandler
    if (fieldMap.getHandler() != null) {

      Class handlerClass = resolveType(fieldMap.getHandler());

      if (!FieldHandler.class.isAssignableFrom(handlerClass)) {
        String err =
            "The class '"
                + fieldMap.getHandler()
                + "' must implement "
                + FieldHandler.class.getName();
        throw new MappingException(err);
      }

      // -- get default constructor to invoke. We can't use the
      // -- newInstance method unfortunately becaue FieldHandler
      // -- overloads this method
      Constructor constructor = null;
      try {
        constructor = handlerClass.getConstructor(new Class[0]);
        handler = (FieldHandler) constructor.newInstance(new Object[0]);
      } catch (Exception except) {
        String err =
            "The class '" + handlerClass.getName() + "' must have a default public constructor.";
        throw new MappingException(err);
      }

      // -- ExtendedFieldHandler?
      if (handler instanceof ExtendedFieldHandler) {
        exfHandler = (ExtendedFieldHandler) handler;
      }

      // -- Fix for Castor JDO from Steve Vaughan, Castor JDO
      // -- requires FieldHandlerImpl or a ClassCastException
      // -- will be thrown... [KV 20030131 - also make sure this new handler
      // -- doesn't use it's own CollectionHandler otherwise
      // -- it'll cause unwanted calls to the getValue method during
      // -- unmarshalling]
      colHandler = typeInfo.getCollectionHandler();
      typeInfo.setCollectionHandler(null);
      handler = new FieldHandlerImpl(handler, typeInfo);
      typeInfo.setCollectionHandler(colHandler);
      // -- End Castor JDO fix

    }

    boolean generalized = (exfHandler instanceof GeneralizedFieldHandler);

    // -- if generalized we need to change the fieldType to whatever
    // -- is specified in the GeneralizedFieldHandler so that the
    // -- correct getter/setter methods can be found
    FieldHandler custom = handler;
    if (generalized) {
      fieldType = ((GeneralizedFieldHandler) exfHandler).getFieldType();
    }

    if (generalized || (handler == null)) {
      // -- create TypeInfoRef to get new TypeInfo from call
      // -- to createFieldHandler
      TypeInfoReference typeInfoRef = new TypeInfoReference();
      typeInfoRef.typeInfo = typeInfo;
      handler = createFieldHandler(javaClass, fieldType, fieldMap, typeInfoRef);
      if (custom != null) {
        ((GeneralizedFieldHandler) exfHandler).setFieldHandler(handler);
        handler = custom;
      } else {
        typeInfo = typeInfoRef.typeInfo;
      }
    }

    String[] sqlName = sql.getName();

    String[] sqlTypes = getSqlTypes(fieldMap);

    int[] sqlTypeNum;
    if (sqlTypes.length > 0) {
      sqlTypeNum = new int[sqlTypes.length];
      for (int i = 0; i < sqlTypes.length; i++) {
        String sqlTypeString = definition2type(sqlTypes[i]);
        Class sqlType = SQLTypeInfos.sqlTypeName2javaType(sqlTypeString);
        if (_factory != null) {
          sqlType = _factory.adjustSqlType(sqlType);
        }
        sqlTypeNum[i] = SQLTypeInfos.javaType2sqlTypeNum(sqlType);
      }
    } else {
      Class sqlType = typeInfo.getFieldType();
      if (_factory != null) {
        sqlType = _factory.adjustSqlType(sqlType);
      }
      sqlTypeNum = new int[] {SQLTypeInfos.javaType2sqlTypeNum(sqlType)};
    }

    // create FieldDescriptor(Impl) instance, and apply JDO nature
    FieldDescriptorImpl fieldDescriptor =
        new FieldDescriptorImpl(fieldName, typeInfo, handler, fieldMap.getTransient());
    fieldDescriptor.addNature(FieldDescriptorJDONature.class.getName());

    fieldDescriptor.setRequired(fieldMap.getRequired());

    // If we're using an ExtendedFieldHandler we need to set the FieldDescriptor
    if (exfHandler != null) {
      ((FieldHandlerFriend) exfHandler).setFieldDescriptor(fieldDescriptor);
    }

    // if SQL mapping declares transient
    // TODO: cross-check that this should be implemented like this
    if (sql.getTransient()) {
      fieldDescriptor.setTransient(true);
    }

    // set collection type as specified in mapping file
    fieldDescriptor.setCollection(fieldMap.getCollection());

    fieldDescriptor.setComparator(fieldMap.getComparator());
    fieldDescriptor.setCreateMethod(fieldMap.getCreateMethod());
    fieldDescriptor.setGetMethod(fieldMap.getGetMethod());
    fieldDescriptor.setSetMethod(fieldMap.getSetMethod());
    fieldDescriptor.setDirect(fieldMap.getDirect());

    // extract values for 'laziness' from field mapping
    fieldDescriptor.setLazy(isLazy);

    FieldDescriptorJDONature fieldJdoNature = new FieldDescriptorJDONature(fieldDescriptor);

    fieldJdoNature.setTypeConvertor(typeInfo.getConvertorFrom());
    if (sqlName.length > 0) {
      fieldJdoNature.setSQLName(sqlName);
    }
    fieldJdoNature.setSQLType(sqlTypeNum);
    fieldJdoNature.setManyTable(sql.getManyTable());
    if (sql.getManyKey().length > 0) {
      fieldJdoNature.setManyKey(sql.getManyKey());
    }
    fieldJdoNature.setDirtyCheck(!SqlDirtyType.IGNORE.equals(sql.getDirty()));
    fieldJdoNature.setReadOnly(sql.getReadOnly());

    fieldJdoNature.setCascading(sql.getCascading());
    fieldJdoNature.setTransient(sql.getTransient());

    return fieldDescriptor;
  }
  protected TypeInfo getTypeInfo(
      final Class fieldType, final CollectionHandler colHandler, final FieldMapping fieldMap)
      throws MappingException {
    Class internalFieldType = Types.typeFromPrimitive(fieldType);
    String typeName = null;
    Class sqlType = null;
    String sqlParam = null;

    String[] sqlTypes = getSqlTypes(fieldMap);
    if ((fieldMap.getSql() != null) && (sqlTypes.length > 0)) {
      // --TO Check
      typeName = sqlTypes[0];
      sqlType = SQLTypeInfos.sqlTypeName2javaType(definition2type(typeName));
      sqlParam = definition2param(typeName);
    } else {
      sqlType = internalFieldType;
    }

    if (_factory != null) {
      sqlType = _factory.adjustSqlType(sqlType);
    }

    TypeConvertor convertorTo = null;
    TypeConvertor convertorFrom = null;

    if (internalFieldType != sqlType) {
      try {
        convertorTo = _typeConvertorRegistry.getConvertor(sqlType, internalFieldType, sqlParam);
      } catch (MappingException ex) {
        boolean isTypeSafeEnum = false;
        // -- check for type-safe enum style classes
        if ((internalFieldType != null) && (!isPrimitive(internalFieldType))) {
          // -- make sure no default constructor
          Constructor cons = null;
          try {
            cons = internalFieldType.getConstructor(EMPTY_ARGS);
            if (!Modifier.isPublic(cons.getModifiers())) {
              cons = null;
            }
          } catch (NoSuchMethodException nsmx) {
            // -- Do nothing
          }

          if (cons == null) {
            // -- make sure a valueOf factory method exists
            try {
              Method method = internalFieldType.getMethod(VALUE_OF, STRING_ARG);
              Class returnType = method.getReturnType();
              if ((returnType != null) && internalFieldType.isAssignableFrom(returnType)) {
                int mods = method.getModifiers();
                if (Modifier.isStatic(mods)) {
                  // create individual SQLTypeConverter
                  convertorTo = new String2EnumTypeConvertor(sqlType, internalFieldType, method);

                  Types.addEnumType(internalFieldType);

                  isTypeSafeEnum = true;
                }
              }
            } catch (NoSuchMethodException nsmx) {
              // -- Do nothing
            }
          }

          if (isTypeSafeEnum) {
            // -- check if name() method should be used instead of toString()
            try {
              Method method = internalFieldType.getMethod(NAME);
              if (String.class == method.getReturnType()) {
                convertorFrom = new Enum2StringTypeConvertor(internalFieldType, sqlType, method);
              }
            } catch (NoSuchMethodException nsmx) {
              // -- Do nothing
            }
          }
        }

        if (!isTypeSafeEnum) {
          throw new MappingException(
              "mapping.noConvertor", sqlType.getName(), internalFieldType.getName());
        }
      }

      if (convertorFrom == null) {
        convertorFrom = _typeConvertorRegistry.getConvertor(internalFieldType, sqlType, sqlParam);
      }

      if ((convertorTo != null) && (convertorFrom != null)) {
        Types.addConvertibleType(internalFieldType);
      }
    }

    return new TypeInfo(
        internalFieldType, convertorTo, convertorFrom, fieldMap.getRequired(), null, colHandler);
  }
예제 #4
0
 public QueryExpression getQueryExpression() {
   return _factory.getQueryExpression();
 }
예제 #5
0
  /**
   * Gives a possibility to patch the Castor-generated SQL statement for INSERT (makes sense for
   * DURING_INSERT key generators)
   */
  public String patchSQL(String insert, String primKeyName) throws MappingException {
    StringTokenizer st;
    String tableName;
    String seqName;
    String nextval;
    StringBuffer sb;
    int lp1; // the first left parenthesis, which starts fields list
    int lp2; // the second left parenthesis, which starts values list

    if (_style == BEFORE_INSERT) {
      return insert;
    }

    // First find the table name
    st = new StringTokenizer(insert);
    if (!st.hasMoreTokens() || !st.nextToken().equalsIgnoreCase("INSERT")) {
      throw new MappingException(Messages.format("mapping.keyGenCannotParse", insert));
    }
    if (!st.hasMoreTokens() || !st.nextToken().equalsIgnoreCase("INTO")) {
      throw new MappingException(Messages.format("mapping.keyGenCannotParse", insert));
    }
    if (!st.hasMoreTokens()) {
      throw new MappingException(Messages.format("mapping.keyGenCannotParse", insert));
    }
    tableName = st.nextToken();

    // remove every double quote in the tablename
    int idxQuote = tableName.indexOf('"');
    if (idxQuote >= 0) {
      StringBuffer buffer2 = new StringBuffer();
      int pos = 0;

      do {
        buffer2.append(tableName.substring(pos, idxQuote));
        pos = idxQuote + 1;
      } while ((idxQuote = tableName.indexOf('"', pos)) != -1);

      buffer2.append(tableName.substring(pos));

      tableName = buffer2.toString();
    }

    seqName =
        MessageFormat.format(
            _seqName,
            new String[] {tableName, primKeyName}); // due to varargs in 1.5, see CASTOR-1097
    nextval = _factory.quoteName(seqName + ".nextval");
    lp1 = insert.indexOf('(');
    lp2 = insert.indexOf('(', lp1 + 1);
    if (lp1 < 0) {
      throw new MappingException(Messages.format("mapping.keyGenCannotParse", insert));
    }
    sb = new StringBuffer(insert);
    if (!_triggerPresent) { // if no onInsert triggers in the DB, we have to supply the Key values
                            // manually
      if (lp2 < 0) {
        // Only one pk field in the table, the INSERT statement would be
        // INSERT INTO table VALUES ()
        lp2 = lp1;
        lp1 = insert.indexOf(" VALUES ");
        // don't change the order of lines below,
        // otherwise index becomes invalid
        sb.insert(lp2 + 1, nextval);
        sb.insert(lp1 + 1, "(" + _factory.quoteName(primKeyName) + ") ");
      } else {
        // don't change the order of lines below,
        // otherwise index becomes invalid
        sb.insert(lp2 + 1, nextval + ",");
        sb.insert(lp1 + 1, _factory.quoteName(primKeyName) + ",");
      }
    }
    if (_style == DURING_INSERT) {
      // append 'RETURNING primKeyName INTO ?'
      sb.append(" RETURNING ");
      sb.append(_factory.quoteName(primKeyName));
      sb.append(" INTO ?");
    }
    return sb.toString();
  }
예제 #6
0
  /**
   * @param conn An open connection within the given transaction
   * @param tableName The table name
   * @param primKeyName The primary key name
   * @param props A temporary replacement for Principal object
   * @return A new key
   * @throws PersistenceException An error occured talking to persistent storage
   */
  public Object generateKey(Connection conn, String tableName, String primKeyName, Properties props)
      throws PersistenceException {
    PreparedStatement stmt = null;
    ResultSet rs;
    String seqName;
    String table;

    seqName =
        MessageFormat.format(
            _seqName,
            new String[] {tableName, primKeyName}); // due to varargs in 1.5, see CASTOR-1097
    table = _factory.quoteName(tableName);
    try {
      if (_factory.getFactoryName().equals(InterbaseFactory.FACTORY_NAME)) {
        // interbase only does before_insert, and does it its own way
        stmt =
            conn.prepareStatement(
                "SELECT gen_id(" + seqName + "," + _increment + ") FROM rdb$database");
        rs = stmt.executeQuery();
      } else if (_factory.getFactoryName().equals(DB2Factory.FACTORY_NAME)) {
        stmt = conn.prepareStatement("SELECT nextval FOR " + seqName + " FROM SYSIBM.SYSDUMMY1");
        rs = stmt.executeQuery();
      } else {
        if (_style == BEFORE_INSERT) {
          stmt = conn.prepareStatement("SELECT nextval('" + seqName + "')");
          rs = stmt.executeQuery();
        } else if (_triggerPresent && _factoryName.equals(PostgreSQLFactory.FACTORY_NAME)) {
          Object insStmt = props.get("insertStatement");
          Class psqlStmtClass = Class.forName("org.postgresql.Statement");
          Method getInsertedOID = psqlStmtClass.getMethod("getInsertedOID", (Class[]) null);
          int insertedOID = ((Integer) getInsertedOID.invoke(insStmt, (Object[]) null)).intValue();
          stmt =
              conn.prepareStatement(
                  "SELECT " + _factory.quoteName(primKeyName) + " FROM " + table + " WHERE OID=?");
          stmt.setInt(1, insertedOID);
          rs = stmt.executeQuery();

        } else {
          stmt =
              conn.prepareStatement(
                  "SELECT " + _factory.quoteName(seqName + ".currval") + " FROM " + table);
          rs = stmt.executeQuery();
        }
      }

      if (!rs.next()) {
        throw new PersistenceException(
            Messages.format("persist.keyGenFailed", getClass().getName()));
      }

      Object resultKey = null;
      int resultValue = rs.getInt(1);
      String resultColName = rs.getMetaData().getColumnName(1);
      int resultColType = rs.getMetaData().getColumnType(1);
      if (LOG.isDebugEnabled()) {
        LOG.debug(
            "JDBC query returned value "
                + resultValue
                + " from column "
                + resultColName
                + "/"
                + resultColType);
      }
      if (_sqlType == Types.INTEGER) {
        resultKey = new Integer(resultValue);
      } else if (_sqlType == Types.BIGINT) {
        resultKey = new Long(resultValue);
      } else if (_sqlType == Types.CHAR || _sqlType == Types.VARCHAR) {
        resultKey = String.valueOf(resultValue);
      } else {
        resultKey = new BigDecimal(resultValue);
      }

      if (LOG.isDebugEnabled()) {
        if (resultKey != null) {
          LOG.debug(
              "Returning value "
                  + resultKey
                  + " of type "
                  + resultKey.getClass().getName()
                  + " as key.");
        }
      }
      return resultKey;
    } catch (Exception ex) {
      throw new PersistenceException(
          Messages.format("persist.keyGenSQL", getClass().getName(), ex.toString()));
    } finally {
      JDOUtils.closeStatement(stmt);
    }
  }