Search in sources :

Example 46 with DatastoreClass

use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.

the class RDBMSStoreManager method getDatastoreClass.

/**
 * Returns the primary datastore table serving as backing for the given class.
 * If the class is not yet known to the store manager, {@link #manageClasses} is called
 * to add it. Classes which have inheritance strategy of "new-table" and
 * "superclass-table" will return a table here, whereas "subclass-table" will
 * return null since it doesn't have a table as such.
 * <p>
 * @param className Name of the class whose table is be returned.
 * @param clr The ClassLoaderResolver
 * @return The corresponding class table.
 * @exception NoTableManagedException If the given class has no table managed in the database.
 */
public DatastoreClass getDatastoreClass(String className, ClassLoaderResolver clr) {
    DatastoreClass ct = null;
    if (className == null) {
        NucleusLogger.PERSISTENCE.error(Localiser.msg("032015"));
        return null;
    }
    schemaLock.readLock().lock();
    try {
        StoreData sd = storeDataMgr.get(className);
        if (sd != null && sd instanceof RDBMSStoreData) {
            ct = (DatastoreClass) sd.getTable();
            if (ct != null) {
                // Class known about
                return ct;
            }
        }
    } finally {
        schemaLock.readLock().unlock();
    }
    // Class not known so consider adding it to our list of supported classes.
    // Currently we only consider PC classes
    boolean toBeAdded = false;
    if (clr != null) {
        Class cls = clr.classForName(className);
        ApiAdapter api = getApiAdapter();
        if (cls != null && !cls.isInterface() && api.isPersistable(cls)) {
            toBeAdded = true;
        }
    } else {
        toBeAdded = true;
    }
    boolean classKnown = false;
    if (toBeAdded) {
        // Add the class to our supported list
        manageClasses(clr, className);
        // Retry
        schemaLock.readLock().lock();
        try {
            StoreData sd = storeDataMgr.get(className);
            if (sd != null && sd instanceof RDBMSStoreData) {
                classKnown = true;
                ct = (DatastoreClass) sd.getTable();
            }
        } finally {
            schemaLock.readLock().unlock();
        }
    }
    // Note : "subclass-table" inheritance strategies will return null from this method
    if (!classKnown && ct == null) {
        throw new NoTableManagedException(className);
    }
    return ct;
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NoTableManagedException(org.datanucleus.store.rdbms.exceptions.NoTableManagedException) StoreData(org.datanucleus.store.StoreData)

Example 47 with DatastoreClass

use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.

the class RDBMSStoreManager method getClassNameForObjectID.

// ---------------------------------------------------------------------------------------
/**
 * Returns the class corresponding to the given object identity.
 * If the identity is a SCOID, return the SCO class.
 * If the identity is a DatastoreId then returns the associated persistable class name.
 * If the identity is a SingleFieldIdentity then returns the associated persistable class name.
 * If the object is an AppID PK, returns the associated PC class (as far as determinable).
 * If the object id is an application id and the user supplies the "ec" argument then a check can be performed in the datastore where necessary.
 * @param id The identity of some object.
 * @param clr ClassLoader resolver
 * @param ec execution context (optional - to allow check inheritance level in datastore)
 * @return For datastore identity, return the class of the corresponding object.
 *      For application identity, return the class of the corresponding object.
 *      Otherwise returns null if unable to tie as the identity of a particular class.
 */
public String getClassNameForObjectID(Object id, ClassLoaderResolver clr, ExecutionContext ec) {
    if (id instanceof SCOID) {
        // Object is a SCOID
        return ((SCOID) id).getSCOClass();
    }
    // Generate a list of metadata for the roots of inheritance tree(s) that this identity can represent
    // Really ought to be for a single inheritance tree (hence one element in the List) but we allow for
    // a user reusing their PK class in multiple trees
    List<AbstractClassMetaData> rootCmds = new ArrayList<>();
    String className = IdentityUtils.getTargetClassNameForIdentity(id);
    if (className != null) {
        AbstractClassMetaData cmd = getMetaDataManager().getMetaDataForClass(className, clr);
        // Basic error checking
        if (IdentityUtils.isDatastoreIdentity(id) && cmd.getIdentityType() != IdentityType.DATASTORE) {
            throw new NucleusUserException(Localiser.msg("038001", id, cmd.getFullClassName()));
        }
        if (IdentityUtils.isSingleFieldIdentity(id) && (cmd.getIdentityType() != IdentityType.APPLICATION || !cmd.getObjectidClass().equals(id.getClass().getName()))) {
            throw new NucleusUserException(Localiser.msg("038001", id, cmd.getFullClassName()));
        }
        rootCmds.add(cmd);
    } else {
        // Find all of the classes with a PK class of this type
        Collection<AbstractClassMetaData> pkCmds = getMetaDataManager().getClassMetaDataWithApplicationId(id.getClass().getName());
        if (pkCmds != null && pkCmds.size() > 0) {
            Iterator<AbstractClassMetaData> iter = pkCmds.iterator();
            while (iter.hasNext()) {
                AbstractClassMetaData pkCmd = iter.next();
                AbstractClassMetaData cmdToSwap = null;
                boolean toAdd = true;
                Iterator<AbstractClassMetaData> rootCmdIterator = rootCmds.iterator();
                while (rootCmdIterator.hasNext()) {
                    AbstractClassMetaData rootCmd = rootCmdIterator.next();
                    if (rootCmd.isDescendantOf(pkCmd)) {
                        // This cmd is a parent of an existing, so swap them
                        cmdToSwap = rootCmd;
                        toAdd = false;
                        break;
                    } else if (pkCmd.isDescendantOf(rootCmd)) {
                        toAdd = false;
                    }
                }
                if (cmdToSwap != null) {
                    rootCmds.remove(cmdToSwap);
                    rootCmds.add(pkCmd);
                } else if (toAdd) {
                    rootCmds.add(pkCmd);
                }
            }
        }
        if (rootCmds.size() == 0) {
            return null;
        }
    }
    AbstractClassMetaData rootCmd = rootCmds.get(0);
    if (ec != null) {
        // Perform a check on the exact object inheritance level with this key (uses SQL query)
        if (rootCmds.size() == 1) {
            Collection<String> subclasses = getSubClassesForClass(rootCmd.getFullClassName(), true, clr);
            if (!rootCmd.isImplementationOfPersistentDefinition()) {
                // Not persistent interface implementation so check if any subclasses
                if (subclasses == null || subclasses.isEmpty()) {
                    // so we assume it can't be a supertype
                    return rootCmd.getFullClassName();
                // This commented out code simply restricts if other classes are using the table
                /*DatastoreClass primaryTable = getDatastoreClass(rootCmd.getFullClassName(), clr);
                        String[] managedClassesInTable = primaryTable.getManagedClasses();
                        if (managedClassesInTable.length == 1 && managedClassesInTable[0].equals(rootCmd.getFullClassName()))
                        {
                            if (NucleusLogger.PERSISTENCE.isDebugEnabled())
                            {
                                NucleusLogger.PERSISTENCE.debug("Sole candidate for id is " +
                                    rootCmd.getFullClassName() + " and has no subclasses, so returning without checking datastore");
                            }
                            return rootCmd.getFullClassName();
                        }*/
                }
            }
            // Check how many concrete classes we have in this tree, in case only one
            int numConcrete = 0;
            String concreteClassName = null;
            Class rootCls = clr.classForName(rootCmd.getFullClassName());
            if (!Modifier.isAbstract(rootCls.getModifiers())) {
                concreteClassName = rootCmd.getFullClassName();
                numConcrete++;
            }
            if (subclasses != null) {
                for (String subclassName : subclasses) {
                    Class subcls = clr.classForName(subclassName);
                    if (!Modifier.isAbstract(subcls.getModifiers())) {
                        if (concreteClassName == null) {
                            concreteClassName = subclassName;
                        }
                        numConcrete++;
                    }
                }
            }
            if (numConcrete == 1) {
                // Single possible concrete class, so return it
                return concreteClassName;
            }
            // Simple candidate query of this class and subclasses
            if (rootCmd.hasDiscriminatorStrategy()) {
                // Query using discriminator
                if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                    NucleusLogger.PERSISTENCE.debug("Performing query using discriminator on " + rootCmd.getFullClassName() + " and its subclasses to find the class of " + id);
                }
                return RDBMSStoreHelper.getClassNameForIdUsingDiscriminator(this, ec, id, rootCmd);
            }
            // Query using UNION
            if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                NucleusLogger.PERSISTENCE.debug("Performing query using UNION on " + rootCmd.getFullClassName() + " and its subclasses to find the class of " + id);
            }
            return RDBMSStoreHelper.getClassNameForIdUsingUnion(this, ec, id, rootCmds);
        }
        // Multiple possible roots so use UNION statement
        if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
            StringBuilder str = new StringBuilder();
            Iterator<AbstractClassMetaData> rootCmdIter = rootCmds.iterator();
            while (rootCmdIter.hasNext()) {
                AbstractClassMetaData cmd = rootCmdIter.next();
                str.append(cmd.getFullClassName());
                if (rootCmdIter.hasNext()) {
                    str.append(",");
                }
            }
            NucleusLogger.PERSISTENCE.debug("Performing query using UNION on " + str.toString() + " and their subclasses to find the class of " + id);
        }
        return RDBMSStoreHelper.getClassNameForIdUsingUnion(this, ec, id, rootCmds);
    }
    // Check not possible so just return the first root
    if (rootCmds.size() > 1) {
        if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
            NucleusLogger.PERSISTENCE.debug("Id \"" + id + "\" has been determined to be the id of class " + rootCmd.getFullClassName() + " : this is the first of " + rootCmds.size() + " possible, but unable to determine further");
        }
        return rootCmd.getFullClassName();
    }
    if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
        NucleusLogger.PERSISTENCE.debug("Id \"" + id + "\" has been determined to be the id of class " + rootCmd.getFullClassName() + " : unable to determine if actually of a subclass");
    }
    return rootCmd.getFullClassName();
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ArrayList(java.util.ArrayList) SCOID(org.datanucleus.identity.SCOID) MacroString(org.datanucleus.util.MacroString) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass)

Example 48 with DatastoreClass

use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.

the class RDBMSStoreManager method resolveIdentifierMacro.

/**
 * Resolves an identifier macro. The public fields <var>className</var>, <var>fieldName </var>,
 * and <var>subfieldName </var> of the given macro are taken as inputs, and the public
 * <var>value </var> field is set to the SQL identifier of the corresponding database table or column.
 * @param im The macro to resolve.
 * @param clr The ClassLoaderResolver
 */
public void resolveIdentifierMacro(MacroString.IdentifierMacro im, ClassLoaderResolver clr) {
    DatastoreClass ct = getDatastoreClass(im.className, clr);
    if (im.fieldName == null) {
        im.value = ct.getIdentifier().toString();
        return;
    }
    JavaTypeMapping m;
    if (// TODO This should be candidate alias or something, not hardcoded "this"
    im.fieldName.equals("this")) {
        if (!(ct instanceof ClassTable)) {
            throw new NucleusUserException(Localiser.msg("050034", im.className));
        }
        if (im.subfieldName != null) {
            throw new NucleusUserException(Localiser.msg("050035", im.className, im.fieldName, im.subfieldName));
        }
        m = ((Table) ct).getIdMapping();
    } else {
        AbstractClassMetaData cmd = getMetaDataManager().getMetaDataForClass(im.className, clr);
        AbstractMemberMetaData mmd = cmd.getMetaDataForMember(im.fieldName);
        m = ct.getMemberMapping(mmd);
        Table t = getTable(mmd);
        if (im.subfieldName == null) {
            if (t != null) {
                im.value = t.getIdentifier().toString();
                return;
            }
        } else {
            if (t instanceof CollectionTable) {
                CollectionTable collTable = (CollectionTable) t;
                if (im.subfieldName.equals("owner")) {
                    m = collTable.getOwnerMapping();
                } else if (im.subfieldName.equals("element")) {
                    m = collTable.getElementMapping();
                } else if (im.subfieldName.equals("index")) {
                    m = collTable.getOrderMapping();
                } else {
                    throw new NucleusUserException(Localiser.msg("050036", im.subfieldName, im));
                }
            } else if (t instanceof MapTable) {
                MapTable mt = (MapTable) t;
                if (im.subfieldName.equals("owner")) {
                    m = mt.getOwnerMapping();
                } else if (im.subfieldName.equals("key")) {
                    m = mt.getKeyMapping();
                } else if (im.subfieldName.equals("value")) {
                    m = mt.getValueMapping();
                } else {
                    throw new NucleusUserException(Localiser.msg("050037", im.subfieldName, im));
                }
            } else {
                throw new NucleusUserException(Localiser.msg("050035", im.className, im.fieldName, im.subfieldName));
            }
        }
    }
    im.value = m.getDatastoreMapping(0).getColumn().getIdentifier().toString();
}
Also used : MapTable(org.datanucleus.store.rdbms.table.MapTable) Table(org.datanucleus.store.rdbms.table.Table) ProbeTable(org.datanucleus.store.rdbms.table.ProbeTable) JoinTable(org.datanucleus.store.rdbms.table.JoinTable) ClassTable(org.datanucleus.store.rdbms.table.ClassTable) MapTable(org.datanucleus.store.rdbms.table.MapTable) PersistableJoinTable(org.datanucleus.store.rdbms.table.PersistableJoinTable) ArrayTable(org.datanucleus.store.rdbms.table.ArrayTable) CollectionTable(org.datanucleus.store.rdbms.table.CollectionTable) SequenceTable(org.datanucleus.store.rdbms.valuegenerator.SequenceTable) CollectionTable(org.datanucleus.store.rdbms.table.CollectionTable) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ClassTable(org.datanucleus.store.rdbms.table.ClassTable) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData)

Example 49 with DatastoreClass

use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.

the class RDBMSPersistenceHandler method updateObjectInTable.

/**
 * Convenience method to handle the update into the various tables that this object is persisted into.
 * @param table The table to process
 * @param op ObjectProvider for the object being updated
 * @param clr ClassLoader resolver
 * @param mmds MetaData for the fields being updated
 */
private void updateObjectInTable(DatastoreClass table, ObjectProvider op, ClassLoaderResolver clr, AbstractMemberMetaData[] mmds) {
    if (table instanceof ClassView) {
        throw new NucleusUserException("Cannot perform UpdateRequest on RDBMS view " + table);
    }
    DatastoreClass supertable = table.getSuperDatastoreClass();
    if (supertable != null) {
        // Process the superclass table first
        updateObjectInTable(supertable, op, clr, mmds);
    }
    // Do the actual update of this table
    getUpdateRequest(table, mmds, op.getClassMetaData(), clr).execute(op);
    // Update any secondary tables
    Collection<SecondaryDatastoreClass> secondaryTables = table.getSecondaryDatastoreClasses();
    if (secondaryTables != null) {
        for (SecondaryDatastoreClass secTable : secondaryTables) {
            // Process the secondary table
            updateObjectInTable(secTable, op, clr, mmds);
        }
    }
}
Also used : ClassView(org.datanucleus.store.rdbms.table.ClassView) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass)

Example 50 with DatastoreClass

use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.

the class RDBMSPersistenceHandler method locateObjects.

// ------------------------------ Locate ----------------------------------
public void locateObjects(ObjectProvider[] ops) {
    if (ops == null || ops.length == 0) {
        return;
    }
    ClassLoaderResolver clr = ops[0].getExecutionContext().getClassLoaderResolver();
    Map<DatastoreClass, List<ObjectProvider>> opsByTable = new HashMap<>();
    for (int i = 0; i < ops.length; i++) {
        AbstractClassMetaData cmd = ops[i].getClassMetaData();
        DatastoreClass table = getDatastoreClass(cmd.getFullClassName(), clr);
        // Use root table in hierarchy
        table = table.getBaseDatastoreClass();
        List<ObjectProvider> opList = opsByTable.get(table);
        if (opList == null) {
            opList = new ArrayList<>();
        }
        opList.add(ops[i]);
        opsByTable.put(table, opList);
    }
    Iterator<Map.Entry<DatastoreClass, List<ObjectProvider>>> tableIter = opsByTable.entrySet().iterator();
    while (tableIter.hasNext()) {
        Map.Entry<DatastoreClass, List<ObjectProvider>> entry = tableIter.next();
        DatastoreClass table = entry.getKey();
        List<ObjectProvider> tableOps = entry.getValue();
        // TODO This just uses the base table. Could change to use the most-derived table
        // which would permit us to join to supertables and load more fields during this process
        LocateBulkRequest req = new LocateBulkRequest(table);
        req.execute(tableOps.toArray(new ObjectProvider[tableOps.size()]));
    }
}
Also used : HashMap(java.util.HashMap) ConcurrentReferenceHashMap(org.datanucleus.util.ConcurrentReferenceHashMap) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ArrayList(java.util.ArrayList) List(java.util.List) ObjectProvider(org.datanucleus.state.ObjectProvider) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) LocateBulkRequest(org.datanucleus.store.rdbms.request.LocateBulkRequest) HashMap(java.util.HashMap) ConcurrentReferenceHashMap(org.datanucleus.util.ConcurrentReferenceHashMap) Map(java.util.Map)

Aggregations

DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)87 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)60 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)49 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)48 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)44 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)41 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)35 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)32 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)28 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)26 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)21 MapTable (org.datanucleus.store.rdbms.table.MapTable)19 NucleusException (org.datanucleus.exceptions.NucleusException)18 SecondaryDatastoreClass (org.datanucleus.store.rdbms.table.SecondaryDatastoreClass)15 ArrayList (java.util.ArrayList)14 ExecutionContext (org.datanucleus.ExecutionContext)13 JoinTable (org.datanucleus.store.rdbms.table.JoinTable)13 Table (org.datanucleus.store.rdbms.table.Table)13 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)11 UnboundExpression (org.datanucleus.store.rdbms.sql.expression.UnboundExpression)11