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;
}
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();
}
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();
}
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);
}
}
}
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()]));
}
}
Aggregations