@Override public DatastoreTable getDatastoreClass(String className, ClassLoaderResolver clr) { try { // We see the occasional race condition when multiple threads concurrently // perform an operation using a persistence-capable class for which DataNucleus // has not yet generated the meta-data. The result is usually // AbstractMemberMetaData objects with the same column listed twice in the meta-data. // Locking at this level is a bit more coarse-grained than I'd like but once the // meta-data has been built this will return super fast so it shouldn't be an issue. synchronized (this) { return (DatastoreTable) super.getDatastoreClass(className, clr); } } catch (NoTableManagedException e) { // Our parent class throws this when the class isn't PersistenceCapable also. Class cls = clr.classForName(className); ApiAdapter api = getApiAdapter(); if (cls != null && !cls.isInterface() && !api.isPersistable(cls)) { throw new NoTableManagedException( "Class " + className + " does not seem to have been enhanced. You may want to rerun " + "the enhancer and check for errors in the output."); // Suggest you address why this method is being called before any check on whether it is // persistable // then you can remove this error message } throw e; } }
/** * Method to validate an element against the accepted type. * * @param clr The ClassLoaderResolver * @param element The element to validate * @return Whether it is valid. */ protected boolean validateElementType(ClassLoaderResolver clr, Object element) { if (element == null) { return true; } Class primitiveElementClass = ClassUtils.getPrimitiveTypeForType(element.getClass()); if (primitiveElementClass != null) { // Allow for the element type being primitive, and the user wanting to store its wrapper String elementTypeWrapper = elementType; Class elementTypeClass = clr.classForName(elementType); if (elementTypeClass.isPrimitive()) { elementTypeWrapper = ClassUtils.getWrapperTypeForPrimitiveType(elementTypeClass).getName(); } return clr.isAssignableFrom(elementTypeWrapper, element.getClass()); } String elementType = null; if (ownerMemberMetaData.hasCollection()) { elementType = ownerMemberMetaData.getCollection().getElementType(); } else if (ownerMemberMetaData.hasArray()) { elementType = ownerMemberMetaData.getArray().getElementType(); } else { elementType = this.elementType; } Class elementCls = clr.classForName(elementType); if (!storeMgr.getNucleusContext().getMetaDataManager().isPersistentInterface(elementType) && elementCls.isInterface()) { // Collection of interface types, so check against the available implementations TODO Check // against allowed implementation in metadata String[] clsNames = storeMgr .getNucleusContext() .getMetaDataManager() .getClassesImplementingInterface(elementType, clr); if (clsNames != null && clsNames.length > 0) { for (int i = 0; i < clsNames.length; i++) { if (clsNames[i].equals(element.getClass().getName())) { return true; } } return false; } } return clr.isAssignableFrom(elementType, element.getClass()); }
/** * Method to validate an element against the accepted type. * * @param clr The ClassLoaderResolver * @param element The element to validate * @return Whether it is valid. */ protected boolean validateElementType(ClassLoaderResolver clr, Object element) { if (element == null) { return true; } Class primitiveElementClass = ClassUtils.getPrimitiveTypeForType(element.getClass()); if (primitiveElementClass != null) { // Allow for the element type being primitive, and the user wanting to store its wrapper String elementTypeWrapper = elementType; Class elementTypeClass = clr.classForName(elementType); if (elementTypeClass.isPrimitive()) { elementTypeWrapper = ClassUtils.getWrapperTypeForPrimitiveType(elementTypeClass).getName(); } return clr.isAssignableFrom(elementTypeWrapper, element.getClass()); } return clr.isAssignableFrom(elementType, element.getClass()); }
/* (non-Javadoc) * @see org.datanucleus.jta.TransactionManagerLocator#getTransactionManager(org.datanucleus.ClassLoaderResolver) */ public TransactionManager getTransactionManager(ClassLoaderResolver clr) { Class cls = clr.classForName("com.atomikos.icatch.jta.UserTransactionManager"); try { return (TransactionManager) cls.newInstance(); } catch (Exception e) { NucleusLogger.TRANSACTION.debug( "Exception obtaining Atomikos transaction manager " + e.getMessage()); return null; } }
/** * Utility that does a discriminator candidate query for the specified candidate and subclasses * and returns the class name of the instance that has the specified identity (if any). * * @param storeMgr RDBMS StoreManager * @param ec execution context * @param id The id * @param cmd Metadata for the root candidate class * @return Name of the class with this identity (or null if none found) */ public static String getClassNameForIdUsingDiscriminator( RDBMSStoreManager storeMgr, ExecutionContext ec, Object id, AbstractClassMetaData cmd) { // Check for input error if (cmd == null || id == null) { return null; } SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory(); ClassLoaderResolver clr = ec.getClassLoaderResolver(); DatastoreClass primaryTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr); // Form the query to find which one of these classes has the instance with this id DiscriminatorStatementGenerator stmtGen = new DiscriminatorStatementGenerator( storeMgr, clr, clr.classForName(cmd.getFullClassName()), true, null, null); stmtGen.setOption(SelectStatementGenerator.OPTION_RESTRICT_DISCRIM); SelectStatement sqlStmt = stmtGen.getStatement(); // Select the discriminator JavaTypeMapping discrimMapping = primaryTable.getDiscriminatorMapping(true); SQLTable discrimSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable( sqlStmt, sqlStmt.getPrimaryTable(), discrimMapping); sqlStmt.select(discrimSqlTbl, discrimMapping, null); // Restrict to this id JavaTypeMapping idMapping = primaryTable.getIdMapping(); JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping); SQLExpression sqlFldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping); SQLExpression sqlFldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID"); sqlStmt.whereAnd(sqlFldExpr.eq(sqlFldVal), true); // Perform the query try { ManagedConnection mconn = storeMgr.getConnection(ec); SQLController sqlControl = storeMgr.getSQLController(); if (ec.getSerializeReadForClass(cmd.getFullClassName())) { sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true); } try { PreparedStatement ps = SQLStatementHelper.getPreparedStatementForSQLStatement(sqlStmt, ec, mconn, null, null); String statement = sqlStmt.getSQLText().toSQL(); try { ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps); try { if (rs != null) { while (rs.next()) { DiscriminatorMetaData dismd = discrimMapping.getTable().getDiscriminatorMetaData(); return RDBMSQueryUtils.getClassNameFromDiscriminatorResultSetRow( discrimMapping, dismd, rs, ec); } } } finally { rs.close(); } } finally { sqlControl.closeStatement(mconn, ps); } } finally { mconn.release(); } } catch (SQLException sqe) { NucleusLogger.DATASTORE.error("Exception thrown on querying of discriminator for id", sqe); throw new NucleusDataStoreException(sqe.toString(), sqe); } return null; }
/** * Utility that does a union candidate query for the specified candidate(s) and subclasses and * returns the class name of the instance that has the specified identity (if any). * * @param storeMgr RDBMS StoreManager * @param ec execution context * @param id The id * @param rootCmds Metadata for the classes at the root * @return Name of the class with this identity (or null if none found) */ public static String getClassNameForIdUsingUnion( RDBMSStoreManager storeMgr, ExecutionContext ec, Object id, List<AbstractClassMetaData> rootCmds) { // Check for input error if (rootCmds == null || rootCmds.isEmpty() || id == null) { return null; } SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory(); ClassLoaderResolver clr = ec.getClassLoaderResolver(); // Form a query UNIONing all possible root candidates (and their subclasses) Iterator<AbstractClassMetaData> rootCmdIter = rootCmds.iterator(); AbstractClassMetaData sampleCmd = null; // Metadata for sample class in the tree so we can check if needs locking SelectStatement sqlStmtMain = null; while (rootCmdIter.hasNext()) { AbstractClassMetaData rootCmd = rootCmdIter.next(); DatastoreClass rootTbl = storeMgr.getDatastoreClass(rootCmd.getFullClassName(), clr); if (rootTbl == null) { // Class must be using "subclass-table" (no table of its own) so find where it is AbstractClassMetaData[] subcmds = storeMgr.getClassesManagingTableForClass(rootCmd, clr); if (subcmds == null || subcmds.length == 0) { // No table for this class so ignore } else { for (int i = 0; i < subcmds.length; i++) { UnionStatementGenerator stmtGen = new UnionStatementGenerator( storeMgr, clr, clr.classForName(subcmds[i].getFullClassName()), true, null, null); stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_NUCLEUS_TYPE); if (sqlStmtMain == null) { sampleCmd = subcmds[i]; sqlStmtMain = stmtGen.getStatement(); // WHERE (object id) = ? JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping(); JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping); SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping); SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID"); sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true); } else { SelectStatement sqlStmt = stmtGen.getStatement(); // WHERE (object id) = ? JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping(); JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping); SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping); SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID"); sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true); sqlStmtMain.union(sqlStmt); } } } } else { UnionStatementGenerator stmtGen = new UnionStatementGenerator( storeMgr, clr, clr.classForName(rootCmd.getFullClassName()), true, null, null); stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_NUCLEUS_TYPE); if (sqlStmtMain == null) { sampleCmd = rootCmd; sqlStmtMain = stmtGen.getStatement(); // WHERE (object id) = ? JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping(); JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping); SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping); SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID"); sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true); } else { SelectStatement sqlStmt = stmtGen.getStatement(); // WHERE (object id) = ? JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping(); JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping); SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping); SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID"); sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true); sqlStmtMain.union(sqlStmt); } } } // Perform the query try { ManagedConnection mconn = storeMgr.getConnection(ec); SQLController sqlControl = storeMgr.getSQLController(); if (ec.getSerializeReadForClass(sampleCmd.getFullClassName())) { sqlStmtMain.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true); } try { PreparedStatement ps = SQLStatementHelper.getPreparedStatementForSQLStatement( sqlStmtMain, ec, mconn, null, null); String statement = sqlStmtMain.getSQLText().toSQL(); try { ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps); try { if (rs != null) { while (rs.next()) { try { return rs.getString(UnionStatementGenerator.NUC_TYPE_COLUMN).trim(); } catch (SQLException sqle) { } } } } finally { rs.close(); } } finally { sqlControl.closeStatement(mconn, ps); } } finally { mconn.release(); } } catch (SQLException sqe) { NucleusLogger.DATASTORE.error("Exception with UNION statement", sqe); throw new NucleusDataStoreException(sqe.toString()); } return null; }
/** * Method to initialise the table definition. * * @param clr The ClassLoaderResolver */ public void initialize(ClassLoaderResolver clr) { assertIsUninitialized(); MapMetaData mapmd = mmd.getMap(); if (mapmd == null) { throw new NucleusUserException(Localiser.msg("057017", mmd)); } PrimaryKeyMetaData pkmd = (mmd.getJoinMetaData() != null ? mmd.getJoinMetaData().getPrimaryKeyMetaData() : null); boolean pkColsSpecified = (pkmd != null && pkmd.getColumnMetaData() != null); boolean pkRequired = requiresPrimaryKey(); // Add owner mapping ColumnMetaData[] ownerColmd = null; if (mmd.getJoinMetaData() != null && mmd.getJoinMetaData().getColumnMetaData() != null && mmd.getJoinMetaData().getColumnMetaData().length > 0) { // Column mappings defined at this side (1-N, M-N) // When specified at this side they use the <join> tag ownerColmd = mmd.getJoinMetaData().getColumnMetaData(); } ownerMapping = ColumnCreator.createColumnsForJoinTables( clr.classForName(ownerType), mmd, ownerColmd, storeMgr, this, pkRequired, false, FieldRole.ROLE_OWNER, clr); if (NucleusLogger.DATASTORE.isDebugEnabled()) { logMapping(mmd.getFullFieldName() + ".[OWNER]", ownerMapping); } String keyValueFieldName = (mmd.getKeyMetaData() != null ? mmd.getKeyMetaData().getMappedBy() : null); String valueKeyFieldName = (mmd.getValueMetaData() != null ? mmd.getValueMetaData().getMappedBy() : null); // Add key mapping boolean keyPC = (mmd.hasMap() && mmd.getMap().keyIsPersistent()); Class keyCls = clr.classForName(mapmd.getKeyType()); if (keyValueFieldName != null && isEmbeddedValuePC()) { // Added in value code } else if (isSerialisedKey() || isEmbeddedKeyPC() || (isEmbeddedKey() && !keyPC) || ClassUtils.isReferenceType(keyCls)) { // Key = PC(embedded), PC(serialised), Non-PC(serialised), Non-PC(embedded), Reference keyMapping = storeMgr.getMappingManager().getMapping(this, mmd, clr, FieldRole.ROLE_MAP_KEY); if (Boolean.TRUE.equals(mmd.getContainer().allowNulls())) { // Make all key col(s) nullable so we can store null elements for (int i = 0; i < keyMapping.getNumberOfDatastoreMappings(); i++) { Column elementCol = keyMapping.getDatastoreMapping(i).getColumn(); elementCol.setNullable(true); } } if (NucleusLogger.DATASTORE.isDebugEnabled()) { logMapping(mmd.getFullFieldName() + ".[KEY]", keyMapping); } if (valueKeyFieldName != null && isEmbeddedKeyPC()) { // Key (PC) is embedded and value is a field of the key EmbeddedKeyPCMapping embMapping = (EmbeddedKeyPCMapping) keyMapping; valueMapping = embMapping.getJavaTypeMapping(valueKeyFieldName); } } else { // Key = PC ColumnMetaData[] keyColmd = null; KeyMetaData keymd = mmd.getKeyMetaData(); if (keymd != null && keymd.getColumnMetaData() != null && keymd.getColumnMetaData().length > 0) { // Column mappings defined at this side (1-N, M-N) keyColmd = keymd.getColumnMetaData(); } keyMapping = ColumnCreator.createColumnsForJoinTables( keyCls, mmd, keyColmd, storeMgr, this, false, false, FieldRole.ROLE_MAP_KEY, clr); if (mmd.getContainer().allowNulls() == Boolean.TRUE) { // Make all key col(s) nullable so we can store null elements for (int i = 0; i < keyMapping.getNumberOfDatastoreMappings(); i++) { Column elementCol = keyMapping.getDatastoreMapping(i).getColumn(); elementCol.setNullable(true); } } if (NucleusLogger.DATASTORE.isDebugEnabled()) { logMapping(mmd.getFullFieldName() + ".[KEY]", keyMapping); } } // Add value mapping boolean valuePC = (mmd.hasMap() && mmd.getMap().valueIsPersistent()); Class valueCls = clr.classForName(mapmd.getValueType()); if (valueKeyFieldName != null && isEmbeddedKeyPC()) { // Added in key code } else if (isSerialisedValue() || isEmbeddedValuePC() || (isEmbeddedValue() && !valuePC) || ClassUtils.isReferenceType(valueCls)) { // Value = PC(embedded), PC(serialised), Non-PC(serialised), Non-PC(embedded), Reference valueMapping = storeMgr.getMappingManager().getMapping(this, mmd, clr, FieldRole.ROLE_MAP_VALUE); if (mmd.getContainer().allowNulls() == Boolean.TRUE) { // Make all value col(s) nullable so we can store null elements for (int i = 0; i < valueMapping.getNumberOfDatastoreMappings(); i++) { Column elementCol = valueMapping.getDatastoreMapping(i).getColumn(); elementCol.setNullable(true); } } if (NucleusLogger.DATASTORE.isDebugEnabled()) { logMapping(mmd.getFullFieldName() + ".[VALUE]", valueMapping); } if (keyValueFieldName != null && isEmbeddedValuePC()) { // Value (PC) is embedded and key is a field of the value EmbeddedValuePCMapping embMapping = (EmbeddedValuePCMapping) valueMapping; keyMapping = embMapping.getJavaTypeMapping(keyValueFieldName); } } else { // Value = PC ColumnMetaData[] valueColmd = null; ValueMetaData valuemd = mmd.getValueMetaData(); if (valuemd != null && valuemd.getColumnMetaData() != null && valuemd.getColumnMetaData().length > 0) { // Column mappings defined at this side (1-N, M-N) valueColmd = valuemd.getColumnMetaData(); } valueMapping = ColumnCreator.createColumnsForJoinTables( clr.classForName(mapmd.getValueType()), mmd, valueColmd, storeMgr, this, false, true, FieldRole.ROLE_MAP_VALUE, clr); if (mmd.getContainer().allowNulls() == Boolean.TRUE) { // Make all value col(s) nullable so we can store null elements for (int i = 0; i < valueMapping.getNumberOfDatastoreMappings(); i++) { Column elementCol = valueMapping.getDatastoreMapping(i).getColumn(); elementCol.setNullable(true); } } if (NucleusLogger.DATASTORE.isDebugEnabled()) { logMapping(mmd.getFullFieldName() + ".[VALUE]", valueMapping); } } // Add order mapping if required boolean orderRequired = false; if (mmd.getOrderMetaData() != null) { // User requested order column so add one orderRequired = true; } else if (requiresPrimaryKey() && !pkColsSpecified) { // PK is required so maybe need to add an index to form the PK if (isEmbeddedKeyPC()) { if (mmd.getMap().getKeyClassMetaData(clr, storeMgr.getMetaDataManager()).getIdentityType() != IdentityType.APPLICATION) { // Embedded key PC with datastore id so we need an index to form the PK orderRequired = true; } } else if (isSerialisedKey()) { // Serialised key, so need an index to form the PK orderRequired = true; } else if (keyMapping instanceof ReferenceMapping) { // ReferenceMapping, so have order if more than 1 implementation ReferenceMapping refMapping = (ReferenceMapping) keyMapping; if (refMapping.getJavaTypeMapping().length > 1) { orderRequired = true; } } else if (!(keyMapping instanceof PersistableMapping)) { // Non-PC, so depends if the key column can be used as part of a PK // TODO This assumes the keyMapping has a single column but what if it is Color with 4 cols? Column elementCol = keyMapping.getDatastoreMapping(0).getColumn(); if (!storeMgr.getDatastoreAdapter().isValidPrimaryKeyType(elementCol.getJdbcType())) { // Not possible to use this Non-PC type as part of the PK orderRequired = true; } } } if (orderRequired) { // Order/Adapter (index) column is required (integer based) ColumnMetaData orderColmd = null; if (mmd.getOrderMetaData() != null && mmd.getOrderMetaData().getColumnMetaData() != null && mmd.getOrderMetaData().getColumnMetaData().length > 0) { // Specified "order" column info orderColmd = mmd.getOrderMetaData().getColumnMetaData()[0]; if (orderColmd.getName() == null) { // No column name so use default orderColmd = new ColumnMetaData(orderColmd); DatastoreIdentifier id = storeMgr.getIdentifierFactory().newIndexFieldIdentifier(mmd); orderColmd.setName(id.getName()); } } else { // No column name so use default DatastoreIdentifier id = storeMgr.getIdentifierFactory().newIndexFieldIdentifier(mmd); orderColmd = new ColumnMetaData(); orderColmd.setName(id.getName()); } orderMapping = storeMgr .getMappingManager() .getMapping(int.class); // JDO2 spec [18.5] order column is assumed to be "int" ColumnCreator.createIndexColumn( orderMapping, storeMgr, clr, this, orderColmd, pkRequired && !pkColsSpecified); if (NucleusLogger.DATASTORE.isDebugEnabled()) { logMapping(mmd.getFullFieldName() + ".[ORDER]", orderMapping); } } // Define primary key of the join table (if any) if (pkRequired) { if (pkColsSpecified) { // Apply the users PK specification applyUserPrimaryKeySpecification(pkmd); } else { // Define PK using internal rules if (orderRequired) { // Order column specified so owner+order are the PK orderMapping.getDatastoreMapping(0).getColumn().setPrimaryKey(); } else { // No order column specified so owner+key are the PK for (int i = 0; i < keyMapping.getNumberOfDatastoreMappings(); i++) { keyMapping.getDatastoreMapping(i).getColumn().setPrimaryKey(); } } } } if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled()) { NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("057023", this)); } storeMgr.registerTableInitialized(this); state = TABLE_STATE_INITIALIZED; }
/** * Method to populate any defaults, and check the validity of the MetaData. * * @param clr ClassLoaderResolver to use for loading any key/value types * @param primary the primary ClassLoader to use (or null) * @param mmgr MetaData manager */ public void populate(ClassLoaderResolver clr, ClassLoader primary, MetaDataManager mmgr) { AbstractMemberMetaData mmd = (AbstractMemberMetaData) parent; if (!StringUtils.isWhitespace(key.type) && key.type.indexOf(',') > 0) { throw new InvalidMetaDataException(LOCALISER, "044143", mmd.getName(), mmd.getClassName()); } if (!StringUtils.isWhitespace(value.type) && value.type.indexOf(',') > 0) { throw new InvalidMetaDataException(LOCALISER, "044144", mmd.getName(), mmd.getClassName()); } ApiAdapter api = mmgr.getApiAdapter(); // Make sure the type in "key", "value" is set key.populate( ((AbstractMemberMetaData) parent).getAbstractClassMetaData().getPackageName(), clr, primary, mmgr); value.populate( ((AbstractMemberMetaData) parent).getAbstractClassMetaData().getPackageName(), clr, primary, mmgr); // Check the field type and see if it is castable to a Map Class field_type = getMemberMetaData().getType(); if (!java.util.Map.class.isAssignableFrom(field_type)) { throw new InvalidMetaDataException( LOCALISER, "044145", getFieldName(), getMemberMetaData().getClassName(false)); } if (java.util.Properties.class.isAssignableFrom(field_type)) { // Properties defaults to <String, String> if (key.type == null) { key.type = String.class.getName(); } if (value.type == null) { value.type = String.class.getName(); } } // "key-type" if (key.type == null) { throw new InvalidMetaDataException( LOCALISER, "044146", getFieldName(), getMemberMetaData().getClassName(false)); } // Check that the key type exists Class keyTypeClass = null; try { keyTypeClass = clr.classForName(key.type, primary); } catch (ClassNotResolvedException cnre) { try { // Maybe the user specified a java.lang class without fully-qualifying it // This is beyond the scope of the JDO spec which expects java.lang cases to be // fully-qualified keyTypeClass = clr.classForName(ClassUtils.getJavaLangClassForType(key.type), primary); } catch (ClassNotResolvedException cnre2) { throw new InvalidMetaDataException( LOCALISER, "044147", getFieldName(), getMemberMetaData().getClassName(false), key.type); } } if (!keyTypeClass.getName().equals(key.type)) { // The value-type has been resolved from what was specified in the MetaData - update to the // fully-qualified name NucleusLogger.METADATA.info( LOCALISER.msg( "044148", getFieldName(), getMemberMetaData().getClassName(false), key.type, keyTypeClass.getName())); key.type = keyTypeClass.getName(); } // "embedded-key" if (key.embedded == null) { // Assign default for "embedded-key" based on 18.13.2 of JDO 2 spec if (mmgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(keyTypeClass)) { key.embedded = Boolean.TRUE; } else if (api.isPersistable(keyTypeClass) || Object.class.isAssignableFrom(keyTypeClass) || keyTypeClass.isInterface()) { key.embedded = Boolean.FALSE; } else { key.embedded = Boolean.TRUE; } } if (Boolean.FALSE.equals(key.embedded)) { // If the user has set a non-PC/non-Interface as not embedded, correct it since not supported. // Note : this fails when using in the enhancer since not yet PC if (!api.isPersistable(keyTypeClass) && !keyTypeClass.isInterface() && keyTypeClass != java.lang.Object.class) { key.embedded = Boolean.TRUE; } } KeyMetaData keymd = ((AbstractMemberMetaData) parent).getKeyMetaData(); if (keymd != null && keymd.getEmbeddedMetaData() != null) { // If the user has specified <embedded>, set to true key.embedded = Boolean.TRUE; } // "value-type" if (value.type == null) { throw new InvalidMetaDataException( LOCALISER, "044149", getFieldName(), getMemberMetaData().getClassName(false)); } // Check that the value-type exists Class valueTypeClass = null; try { valueTypeClass = clr.classForName(value.type); } catch (ClassNotResolvedException cnre) { try { // Maybe the user specified a java.lang class without fully-qualifying it // This is beyond the scope of the JDO spec which expects java.lang cases to be // fully-qualified valueTypeClass = clr.classForName(ClassUtils.getJavaLangClassForType(value.type)); } catch (ClassNotResolvedException cnre2) { throw new InvalidMetaDataException( LOCALISER, "044150", getFieldName(), getMemberMetaData().getClassName(false), value.type); } } if (!valueTypeClass.getName().equals(value.type)) { // The value-type has been resolved from what was specified in the MetaData - update to the // fully-qualified name NucleusLogger.METADATA.info( LOCALISER.msg( "044151", getFieldName(), getMemberMetaData().getClassName(false), value.type, valueTypeClass.getName())); value.type = valueTypeClass.getName(); } // "embedded-value" if (value.embedded == null) { // Assign default for "embedded-value" based on 18.13.2 of JDO 2 spec if (mmgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(valueTypeClass)) { value.embedded = Boolean.TRUE; } else if (api.isPersistable(valueTypeClass) || Object.class.isAssignableFrom(valueTypeClass) || valueTypeClass.isInterface()) { value.embedded = Boolean.FALSE; } else { value.embedded = Boolean.TRUE; } } if (value.embedded == Boolean.FALSE) { // If the user has set a non-PC/non-Interface as not embedded, correct it since not supported. // Note : this fails when using in the enhancer since not yet PC if (!api.isPersistable(valueTypeClass) && !valueTypeClass.isInterface() && valueTypeClass != java.lang.Object.class) { value.embedded = Boolean.TRUE; } } ValueMetaData valuemd = ((AbstractMemberMetaData) parent).getValueMetaData(); if (valuemd != null && valuemd.getEmbeddedMetaData() != null) { // If the user has specified <embedded>, set to true value.embedded = Boolean.TRUE; } key.classMetaData = mmgr.getMetaDataForClassInternal(keyTypeClass, clr); value.classMetaData = mmgr.getMetaDataForClassInternal(valueTypeClass, clr); // Cater for Key with mapped-by needing to be PK (for JPA) if (keymd != null && keymd.mappedBy != null && keymd.mappedBy.equals("#PK")) // Special value set by JPAMetaDataHandler { // Need to set the mapped-by of <key> to be the PK of the <value> if (value.classMetaData.getNoOfPrimaryKeyMembers() != 1) { // TODO Localise this throw new NucleusUserException( "DataNucleus does not support use of <map-key> with no name field when the" + " value class has a composite primary key"); } int[] valuePkFieldNums = value.classMetaData.getPKMemberPositions(); keymd.mappedBy = value.classMetaData.getMetaDataForManagedMemberAtAbsolutePosition(valuePkFieldNums[0]) .name; } // Make sure anything in the superclass is populated too super.populate(clr, primary, mmgr); setPopulated(); }
/** * Utility to create the application identity columns and mapping. Uses the id mapping of the * specified class table and copies the mappings and columns, whilst retaining the passed * preferences for column namings. This is used to copy the PK mappings of a superclass table so * we have the same PK. * * @param columnContainer The container of column MetaData with any namings * @param refTable The table that we use as reference * @param clr The ClassLoaderResolver * @param cmd The ClassMetaData */ final void addApplicationIdUsingClassTableId( ColumnMetaDataContainer columnContainer, DatastoreClass refTable, ClassLoaderResolver clr, AbstractClassMetaData cmd) { ColumnMetaData[] userdefinedCols = null; int nextUserdefinedCol = 0; if (columnContainer != null) { userdefinedCols = columnContainer.getColumnMetaData(); } pkMappings = new JavaTypeMapping[cmd.getPKMemberPositions().length]; for (int i = 0; i < cmd.getPKMemberPositions().length; i++) { AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(cmd.getPKMemberPositions()[i]); JavaTypeMapping mapping = refTable.getMemberMapping(mmd); if (mapping == null) { // probably due to invalid metadata defined by the user throw new NucleusUserException( "Cannot find mapping for field " + mmd.getFullFieldName() + " in table " + refTable.toString() + " " + StringUtils.collectionToString(refTable.getColumns())); } JavaTypeMapping masterMapping = storeMgr.getMappingManager().getMapping(clr.classForName(mapping.getType())); masterMapping.setMemberMetaData(mmd); // Update field info in mapping masterMapping.setTable(this); pkMappings[i] = masterMapping; // Loop through each id column in the reference table and add the same here // applying the required names from the columnContainer for (int j = 0; j < mapping.getNumberOfDatastoreMappings(); j++) { JavaTypeMapping m = masterMapping; Column refColumn = mapping.getDatastoreMapping(j).getColumn(); if (mapping instanceof PersistableMapping) { m = storeMgr .getMappingManager() .getMapping(clr.classForName(refColumn.getJavaTypeMapping().getType())); ((PersistableMapping) masterMapping).addJavaTypeMapping(m); } ColumnMetaData userdefinedColumn = null; if (userdefinedCols != null) { for (int k = 0; k < userdefinedCols.length; k++) { if (refColumn.getIdentifier().toString().equals(userdefinedCols[k].getTarget())) { userdefinedColumn = userdefinedCols[k]; break; } } if (userdefinedColumn == null && nextUserdefinedCol < userdefinedCols.length) { userdefinedColumn = userdefinedCols[nextUserdefinedCol++]; } } // Add this application identity column Column idColumn = null; if (userdefinedColumn != null) { // User has provided a name for this column // Currently we only use the column namings from the users definition but we could easily // take more of their details. idColumn = addColumn( refColumn.getStoredJavaType(), storeMgr .getIdentifierFactory() .newIdentifier(IdentifierType.COLUMN, userdefinedColumn.getName()), m, refColumn.getColumnMetaData()); } else { // No name provided so take same as superclass idColumn = addColumn( refColumn.getStoredJavaType(), refColumn.getIdentifier(), m, refColumn.getColumnMetaData()); } if (mapping.getDatastoreMapping(j).getColumn().getColumnMetaData() != null) { refColumn.copyConfigurationTo(idColumn); } idColumn.setPrimaryKey(); // Set the column type based on the field.getType() getStoreManager() .getMappingManager() .createDatastoreMapping(m, idColumn, refColumn.getJavaTypeMapping().getType()); } // Update highest field number if this is higher int absoluteFieldNumber = mmd.getAbsoluteFieldNumber(); if (absoluteFieldNumber > highestMemberNumber) { highestMemberNumber = absoluteFieldNumber; } } }
/** * Method to return a statement selecting the candidate table(s) required to cover all possible * types for this candidates inheritance strategy. * * @param storeMgr RDBMS StoreManager * @param parentStmt Parent statement (if there is one) * @param cmd Metadata for the class * @param clsMapping Mapping for the results of the statement * @param ec ExecutionContext * @param candidateCls Candidate class * @param subclasses Whether to create a statement for subclasses of the candidate too * @param result The result clause * @param candidateAlias alias for the candidate (if any) * @param candidateTableGroupName TableGroup name for the candidate (if any) * @return The SQLStatement * @throws NucleusException if there are no tables for concrete classes in this query (hence would * return null) */ public static SQLStatement getStatementForCandidates( RDBMSStoreManager storeMgr, SQLStatement parentStmt, AbstractClassMetaData cmd, StatementClassMapping clsMapping, ExecutionContext ec, Class candidateCls, boolean subclasses, String result, String candidateAlias, String candidateTableGroupName) { SQLStatement stmt = null; DatastoreIdentifier candidateAliasId = null; if (candidateAlias != null) { candidateAliasId = storeMgr.getIdentifierFactory().newTableIdentifier(candidateAlias); } ClassLoaderResolver clr = ec.getClassLoaderResolver(); List<DatastoreClass> candidateTables = new ArrayList<DatastoreClass>(); if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) { DatastoreClass candidateTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr); if (candidateTable != null) { candidateTables.add(candidateTable); } if (subclasses) { Collection<String> subclassNames = storeMgr.getSubClassesForClass(cmd.getFullClassName(), subclasses, clr); if (subclassNames != null) { Iterator<String> subclassIter = subclassNames.iterator(); while (subclassIter.hasNext()) { String subclassName = subclassIter.next(); DatastoreClass tbl = storeMgr.getDatastoreClass(subclassName, clr); if (tbl != null) { candidateTables.add(tbl); } } } } Iterator<DatastoreClass> iter = candidateTables.iterator(); int maxClassNameLength = cmd.getFullClassName().length(); while (iter.hasNext()) { DatastoreClass cls = iter.next(); String className = cls.getType(); if (className.length() > maxClassNameLength) { maxClassNameLength = className.length(); } } iter = candidateTables.iterator(); while (iter.hasNext()) { DatastoreClass cls = iter.next(); SQLStatement tblStmt = new SQLStatement(parentStmt, storeMgr, cls, candidateAliasId, candidateTableGroupName); tblStmt.setClassLoaderResolver(clr); tblStmt.setCandidateClassName(cls.getType()); // Add SELECT of dummy column accessible as "NUCLEUS_TYPE" containing the classname JavaTypeMapping m = storeMgr.getMappingManager().getMapping(String.class); String nuctypeName = cls.getType(); if (maxClassNameLength > nuctypeName.length()) { nuctypeName = StringUtils.leftAlignedPaddedString(nuctypeName, maxClassNameLength); } StringLiteral lit = new StringLiteral(tblStmt, m, nuctypeName, null); tblStmt.select(lit, UnionStatementGenerator.NUC_TYPE_COLUMN); if (stmt == null) { stmt = tblStmt; } else { stmt.union(tblStmt); } } if (clsMapping != null) { clsMapping.setNucleusTypeColumnName(UnionStatementGenerator.NUC_TYPE_COLUMN); } } else { // "new-table", "superclass-table", "subclass-table" List<Class> candidateClasses = new ArrayList<Class>(); if (ClassUtils.isReferenceType(candidateCls)) { // Persistent interface, so find all persistent implementations String[] clsNames = storeMgr .getNucleusContext() .getMetaDataManager() .getClassesImplementingInterface(candidateCls.getName(), clr); for (int i = 0; i < clsNames.length; i++) { Class cls = clr.classForName(clsNames[i]); DatastoreClass table = storeMgr.getDatastoreClass(clsNames[i], clr); candidateClasses.add(cls); candidateTables.add(table); AbstractClassMetaData implCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(cls, clr); if (implCmd.getIdentityType() != cmd.getIdentityType()) { throw new NucleusUserException( "You are querying an interface (" + cmd.getFullClassName() + ") " + "yet one of its implementations (" + implCmd.getFullClassName() + ") " + " uses a different identity type!"); } else if (cmd.getIdentityType() == IdentityType.APPLICATION) { if (cmd.getPKMemberPositions().length != implCmd.getPKMemberPositions().length) { throw new NucleusUserException( "You are querying an interface (" + cmd.getFullClassName() + ") " + "yet one of its implementations (" + implCmd.getFullClassName() + ") " + " has a different number of PK members!"); } } } } else { DatastoreClass candidateTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr); if (candidateTable != null) { // Candidate has own table candidateClasses.add(candidateCls); candidateTables.add(candidateTable); } else { // Candidate stored in subclass tables AbstractClassMetaData[] cmds = storeMgr.getClassesManagingTableForClass(cmd, clr); if (cmds != null && cmds.length > 0) { for (int i = 0; i < cmds.length; i++) { DatastoreClass table = storeMgr.getDatastoreClass(cmds[i].getFullClassName(), clr); Class cls = clr.classForName(cmds[i].getFullClassName()); candidateClasses.add(cls); candidateTables.add(table); } } else { throw new UnsupportedOperationException( "No tables for query of " + cmd.getFullClassName()); } } } for (int i = 0; i < candidateTables.size(); i++) { DatastoreClass tbl = candidateTables.get(i); Class cls = candidateClasses.get(i); StatementGenerator stmtGen = null; if (tbl.getDiscriminatorMapping(true) != null || QueryUtils.resultHasOnlyAggregates(result)) { // Either has a discriminator, or only selecting aggregates so need single select stmtGen = new DiscriminatorStatementGenerator( storeMgr, clr, cls, subclasses, candidateAliasId, candidateTableGroupName); stmtGen.setOption(StatementGenerator.OPTION_RESTRICT_DISCRIM); } else { stmtGen = new UnionStatementGenerator( storeMgr, clr, cls, subclasses, candidateAliasId, candidateTableGroupName); if (result == null) { // Returning one row per candidate so include distinguisher column stmtGen.setOption(StatementGenerator.OPTION_SELECT_NUCLEUS_TYPE); clsMapping.setNucleusTypeColumnName(UnionStatementGenerator.NUC_TYPE_COLUMN); } } stmtGen.setParentStatement(parentStmt); SQLStatement tblStmt = stmtGen.getStatement(); if (stmt == null) { stmt = tblStmt; } else { stmt.union(tblStmt); } } } return stmt; }
/** * Method to populate any defaults, and check the validity of the MetaData. * * @param clr ClassLoaderResolver to use for any loading operations * @param primary the primary ClassLoader to use (or null) * @param mmgr MetaData manager */ public void populate(ClassLoaderResolver clr, ClassLoader primary, MetaDataManager mmgr) { AbstractMemberMetaData mmd = (AbstractMemberMetaData) parent; if (!StringUtils.isWhitespace(element.type) && element.type.indexOf(',') > 0) { throw new InvalidMetaDataException(LOCALISER, "044131", mmd.getName(), mmd.getClassName()); } // Make sure the type in "element" is set element.populate( ((AbstractMemberMetaData) parent).getAbstractClassMetaData().getPackageName(), clr, primary, mmgr); // Check the field type and see if it is castable to a Collection Class field_type = getMemberMetaData().getType(); if (!java.util.Collection.class.isAssignableFrom(field_type)) { throw new InvalidMetaDataException( LOCALISER, "044132", getFieldName(), getMemberMetaData().getClassName(false)); } // "element-type" if (element.type == null) { throw new InvalidMetaDataException( LOCALISER, "044133", getFieldName(), getMemberMetaData().getClassName(false)); } // Check that the element type exists Class elementTypeClass = null; try { elementTypeClass = clr.classForName(element.type, primary); } catch (ClassNotResolvedException cnre) { throw new InvalidMetaDataException( LOCALISER, "044134", getFieldName(), getMemberMetaData().getClassName(false), element.type); } if (!elementTypeClass.getName().equals(element.type)) { // The element-type has been resolved from what was specified in the MetaData - update to the // fully-qualified name NucleusLogger.METADATA.info( LOCALISER.msg( "044135", getFieldName(), getMemberMetaData().getClassName(false), element.type, elementTypeClass.getName())); element.type = elementTypeClass.getName(); } // "embedded-element" ApiAdapter api = mmgr.getApiAdapter(); if (element.embedded == null) { // Assign default for "embedded-element" based on 18.13.1 of JDO 2 spec // Note : this fails when using in the enhancer since not yet PC if (mmgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(elementTypeClass)) { element.embedded = Boolean.TRUE; } else if (api.isPersistable(elementTypeClass) || Object.class.isAssignableFrom(elementTypeClass) || elementTypeClass.isInterface()) { element.embedded = Boolean.FALSE; } else { element.embedded = Boolean.TRUE; } } if (Boolean.FALSE.equals(element.embedded)) { // If the user has set a non-PC/non-Interface as not embedded, correct it since not supported. // Note : this fails when using in the enhancer since not yet PC if (!api.isPersistable(elementTypeClass) && !elementTypeClass.isInterface() && elementTypeClass != java.lang.Object.class) { element.embedded = Boolean.TRUE; } } ElementMetaData elemmd = ((AbstractMemberMetaData) parent).getElementMetaData(); if (elemmd != null && elemmd.getEmbeddedMetaData() != null) { element.embedded = Boolean.TRUE; } if (Boolean.TRUE.equals(element.dependent)) { // If the user has set a non-PC/non-reference as dependent, correct it since not valid. // Note : this fails when using in the enhancer since not yet PC if (!api.isPersistable(elementTypeClass) && !elementTypeClass.isInterface() && elementTypeClass != java.lang.Object.class) { element.dependent = Boolean.FALSE; } } // Keep a reference to the MetaData for the element element.classMetaData = mmgr.getMetaDataForClassInternal(elementTypeClass, clr); // Make sure anything in the superclass is populated too super.populate(clr, primary, mmgr); setPopulated(); }