/**********************************************************************
Copyright (c) 2006 Andy Jefferson and others. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Contributors:
...
**********************************************************************/
package org.jpox.jdo.metadata;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.jpox.ClassLoaderResolver;
import org.jpox.OMFContext;
import org.jpox.exceptions.JPOXException;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.ClassMetaData;
import org.jpox.metadata.FileMetaData;
import org.jpox.metadata.ImplementsMetaData;
import org.jpox.metadata.InterfaceMetaData;
import org.jpox.metadata.MetaDataManager;
import org.jpox.metadata.MetaDataMerger;
import org.jpox.metadata.PackageMetaData;
import org.jpox.metadata.QueryMetaData;
import org.jpox.metadata.SequenceMetaData;
import org.jpox.metadata.xml.MetaDataParser;
import org.jpox.util.JPOXLogger;
import org.jpox.util.StringUtils;
/**
* Manager of JDO MetaData information in JPOX.
* <P>
* Acts as a registry of JDO metadata so that metadata files don't need to be
* parsed multiple times. MetaData is stored as a FileMetaData, which contains
* PackageMetaData, which contains ClassMetaData, and so on. This maps exactly
* to the users model of their metadata. The users access point is
* <B>getMetaDataForClass()</B> which will check the known classes without metadata,
* then check the existing registered metdata, then check the valid locations for
* metdata files. This way, the metadata is managed from this single point.
* </P>
* <P>
* When the MetaData is requested for a class, if it isnt already found, the valid
* file locations are checked for that class and the file containing it will be
* read. The MetaData for all classes, queries, sequences etc in that file are
* loaded at that point. In addition, all classes will be "populated" (meaning that
* their superclasses are assigned, and unspecified fields are added, and any related
* objects are linked). The MetaData of these classes are only initialised when
* they are absolutely needed - to avoid generating circular references in the
* initialisation process.
* </P>
* <P>
* Each PMFContext typically will have its own MetaDataManager so allowing
* Meta-Data to be for different datastores. In addition, each PMF can allow
* MetaData files to use a particular suffix, hence we allow the JDO/ORM file
* suffices to be specifiable at construction.
* </P>
*
* @version $Revision: 1.31 $
*/
public class JDOMetaDataManager extends MetaDataManager
{
/** MetaData files will be searched in all possible locations defined in JDO 1.0, JDO 1.0.1, JDO 2.0 or later **/
public static final int ALL_JDO_LOCATIONS = 1;
/** MetaData files will be searched in all locations defined in JDO 1.0 **/
public static final int JDO_1_0_0_LOCATIONS = 2;
/** MetaData files will be searched in all locations defined in JDO 1.0.1 **/
public static final int JDO_1_0_1_LOCATIONS = 3;
/** Definition of which locations we accept for MetaData files. */
protected int locationDefinition = ALL_JDO_LOCATIONS;
/** Map of ClassMetaData from ORM files, keyed by the class name. */
protected Map ormClassMetaDataByClass = new HashMap();
/**
* Map of ClassMetaData, keyed by the interface class name (for "persistent-interface"s).
* Keyed by the persistent-interface name.
*/
protected Map classMetaDataByInterface = new HashMap();
/**
* Constructor.
* @param ctxt ObjectManagerFactory Context that this metadata manager operates in
*/
public JDOMetaDataManager(OMFContext ctxt)
{
super(ctxt);
locationDefinition = ALL_JDO_LOCATIONS;
// Log the current configuration
if (JPOXLogger.METADATA.isDebugEnabled())
{
logConfiguration();
}
}
/**
* Convenience accessor for the mapping name.
* @return ORM mapping name
*/
protected String getORMMappingName()
{
String mappingName = omfContext.getPersistenceConfiguration().getStringProperty("org.jpox.Mapping");
return (StringUtils.isWhitespace(mappingName) ? null : mappingName);
}
/**
* Convenience accessor for the JDO file suffix.
* @return JDO file suffix
*/
public String getJDOFileSuffix()
{
String suffix = omfContext.getPersistenceConfiguration().getStringProperty("org.jpox.metadata.jdoFileExtension");
return (StringUtils.isWhitespace(suffix) ? "jdo" : suffix);
}
/**
* Convenience accessor for the ORM file suffix.
* @return ORM file suffix
*/
public String getORMFileSuffix()
{
String suffix = omfContext.getPersistenceConfiguration().getStringProperty("org.jpox.metadata.ormFileExtension");
return (StringUtils.isWhitespace(suffix) ? "orm" : suffix);
}
/**
* Convenience accessor for the JDOQuery file suffix.
* @return JDOQuery file suffix
*/
public String getJDOQueryFileSuffix()
{
String suffix = omfContext.getPersistenceConfiguration().getStringProperty("org.jpox.metadata.jdoqueryFileExtension");
return (StringUtils.isWhitespace(suffix) ? "jdoquery" : suffix);
}
/**
* Method to log the configuration of this manager.
*/
protected void logConfiguration()
{
// Log the configuration
String inputTypes = null;
if (annotationManager != null)
{
inputTypes = "XML, Annotations";
}
else
{
inputTypes = "XML";
}
if (JPOXLogger.METADATA.isDebugEnabled())
{
if (supportsORM)
{
String mappingName = getORMMappingName();
String jdoSuffix = getJDOFileSuffix();
String ormSuffix = getORMFileSuffix();
String jdoquerySuffix = getJDOQueryFileSuffix();
JPOXLogger.METADATA.debug("MetaDataManager : " +
" Input=(" + inputTypes + ")" +
" XML-Validation=" + validateMetaData +
" XML-Files=(persistence=*." + jdoSuffix + ", ORM=*." + ormSuffix + ", query=*." + jdoquerySuffix + ")" +
(mappingName != null ? (" ORM-name=" + mappingName) : ""));
}
else
{
String jdoSuffix = getJDOFileSuffix();
String jdoquerySuffix = getJDOQueryFileSuffix();
JPOXLogger.METADATA.debug("MetaDataManager : " +
" Input=(" + inputTypes + ")" +
" XML-Validation=" + validateMetaData +
" XML-Files=(persistence=*." + jdoSuffix + ", query=*." + jdoquerySuffix + ")");
}
}
}
/**
* Clear resources
*/
public void close()
{
super.close();
ormClassMetaDataByClass.clear();
ormClassMetaDataByClass = null;
}
/**
* Utility to parse a file, using the "jdo" MetaData handler.
* @param fileURL URL of the file
* @return The FileMetaData for this file
*/
protected FileMetaData parseFile(URL fileURL)
{
if (metaDataParser == null)
{
metaDataParser = new MetaDataParser(this, validateMetaData);
}
return (FileMetaData)metaDataParser.parseMetaDataURL(fileURL, "jdo");
}
/**
* Method to take the FileMetaData and register the relevant parts of it with the assorted caches provided.
* @param fileURLString URL of the metadata file
* @param filemd The File MetaData
*/
public void registerFile(String fileURLString, FileMetaData filemd, ClassLoaderResolver clr)
{
if (fileURLString == null)
{
// Null file
return;
}
if (fileMetaDataByURLString.get(fileURLString) != null)
{
// Already registered!
return;
}
fileMetaDataByURLString.put(fileURLString, filemd);
registerQueriesForFile(filemd);
registerFetchPlansForFile(filemd);
registerSequencesForFile(filemd);
registerTableGeneratorsForFile(filemd);
// Register the classes and interfaces for later use
if (filemd.getType() != FileMetaData.JDOQUERY_FILE)
{
for (int i = 0; i < filemd.getNoOfPackages(); i++)
{
PackageMetaData pmd = filemd.getPackage(i);
// Register all classes into the respective lookup maps
for (int j = 0; j < pmd.getNoOfClasses(); j++)
{
ClassMetaData cmd = pmd.getClass(j);
if (filemd.getType() == FileMetaData.JDO_FILE || filemd.getType() == FileMetaData.ANNOTATIONS)
{
registerMetaDataForClass(cmd.getFullClassName(), cmd);
}
else if (filemd.getType() == FileMetaData.ORM_FILE)
{
ormClassMetaDataByClass.put(cmd.getFullClassName(), cmd);
}
if (cmd.getEntityName() != null)
{
// Register the ClassMetaData against the "entity name"
classMetaDataByEntityName.put(cmd.getEntityName(), cmd);
}
}
// Register all interfaces into the respective lookup maps
for (int j = 0; j < pmd.getNoOfInterfaces(); j++)
{
InterfaceMetaData intfmd = pmd.getInterface(j);
if (filemd.getType() == FileMetaData.JDO_FILE || filemd.getType() == FileMetaData.ANNOTATIONS)
{
registerMetaDataForClass(intfmd.getFullClassName(), intfmd);
}
else if (filemd.getType() == FileMetaData.ORM_FILE)
{
ormClassMetaDataByClass.put(intfmd.getFullClassName(), intfmd);
}
}
}
}
}
/**
* Convenience method to check if we have metadata present for the specified class.
* @param className The name of the class to check
* @return Whether the metadata is already registered for this class
*/
public boolean hasMetaDataForClass(String className)
{
if (className == null)
{
return false;
}
// Check if this class has no MetaData before instantiating its class
if (isClassWithoutPersistenceInfo(className))
{
return false;
}
return (classMetaDataByClass.get(className) != null);
}
/**
* Internal method for accessing the MetaData for a class.
* The MetaData returned can be uninitialised.
* Runs through the following process
* <OL>
* <LI>Checks if the class is known not to have metata</LI>
* <LI>Check if we have metadata for the class in one of the files that has
* been parsed.</LI>
* <LI>If we have metadata, check that it is initialised</LI>
* <LI>If we don't have metadata, find the file for this class.</LI>
* <LI>If we cant find a file for it, add it to the list of classes known
* to have no metadata</LI>
* </OL>
* @param c The class to find MetaData for
* @return The ClassMetaData for this class (or null if not found)
**/
public synchronized AbstractClassMetaData getMetaDataForClassInternal(Class c, ClassLoaderResolver clr)
{
String className = c.getName();
// If we know that this class/interface has no MetaData/annotations don't bother searching
if (isClassWithoutPersistenceInfo(className))
{
return null;
}
// Check if we have the MetaData already
AbstractClassMetaData the_md = (AbstractClassMetaData) classMetaDataByClass.get(className);
if (the_md != null)
{
return the_md;
}
// No loaded MetaData so search valid location for a file for this class and load all in the process
FileMetaData filemd = loadMetaDataForClass(c, clr, null, getJDOFileSuffix(), true);
if (filemd != null)
{
// Class has had its metadata loaded
utilisedFileMetaData.add(filemd);
// If not MetaData complete will also merge in annotations at populate stage
// Retrieve the MetaData for the requested class
the_md = (AbstractClassMetaData)classMetaDataByClass.get(className);
return the_md;
}
// No MetaData so check for annotations
FileMetaData annFilemd = loadAnnotationsForClass(c, clr, true, true);
if (annFilemd != null)
{
// No MetaData but annotations present so use that
if (c.isInterface())
{
return annFilemd.getPackage(0).getInterface(0);
}
else
{
return annFilemd.getPackage(0).getClass(0);
}
}
// Not found, so add to known classes/interfaces without MetaData
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044043", className));
}
classesWithoutPersistenceInfo.add(className);
return null;
}
/**
* Accessor for the MetaData for a named query for a class.
* If the query is not found, will check all valid JDO file locations and try to load it.
* @param cls The class which has the query defined for it
* @param clr the ClassLoaderResolver
* @param queryName Name of the query
* @return The QueryMetaData for the query for this class
**/
public QueryMetaData getMetaDataForQuery(Class cls, ClassLoaderResolver clr, String queryName)
{
QueryMetaData qmd = super.getMetaDataForQuery(cls, clr, queryName);
if (qmd != null)
{
return qmd;
}
String query_key = queryName;
if (cls != null)
{
query_key = cls.getName() + "_" + queryName;
}
// No query found, so try to load one from a valid JDO location
if (cls != null)
{
// Query is scoped to a candidate class, so load the class as necessary
AbstractClassMetaData cmd = getMetaDataForClass(cls, clr);
if (cmd == null)
{
// No metadata for this class so no chance of finding the query for it
return null;
}
Object obj = queryMetaDataByName.get(query_key);
if (obj != null)
{
return (QueryMetaData)obj;
}
// Query not stored in JDO/ORM files so try JDOQUERY
List locations = new ArrayList();
locations.addAll(getValidMetaDataLocationsForClass(getJDOQueryFileSuffix(), null, cls.getName()));
for (int i=0; i<locations.size(); i++)
{
String location = (String) locations.get(i);
// Process all resources for this location
Enumeration resources;
try
{
resources = clr.getResources(location, cls != null ? cls.getClassLoader() : null);
}
catch (IOException e)
{
throw new JPOXException("Error loading resource", e).setFatal();
}
while (resources.hasMoreElements())
{
URL fileURL = (URL) resources.nextElement();
if (fileMetaDataByURLString.get(fileURL.toString()) == null)
{
// File hasn't been loaded so load it
FileMetaData filemd = parseFile(fileURL);
filemd.setType(FileMetaData.JDOQUERY_FILE); // TODO Remove this since set in the parser at <jdoquery>
registerFile(fileURL.toString(), filemd, clr);
// Populate all classes in this file we've just parsed
// TODO Populate the classes found in this file
}
}
cmd = getMetaDataForClass(cls, clr);
qmd = (QueryMetaData)queryMetaDataByName.get(query_key);
if (qmd != null)
{
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044053",query_key,location));
}
return qmd;
}
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044050",query_key,location));
}
}
return null;
}
// Query isn't scoped to a candidate class, so search the valid package-independent locations
List locations = new ArrayList();
locations.addAll(getValidMetaDataLocationsForItem(getJDOFileSuffix(), null, null, false));
locations.addAll(getValidMetaDataLocationsForItem(getORMFileSuffix(), getORMMappingName(), null, false));
locations.addAll(getValidMetaDataLocationsForItem(getJDOQueryFileSuffix(), null, null, false));
for (int i=0; i<locations.size(); i++)
{
String location = (String) locations.get(i);
// Process all resources for this location
Enumeration resources;
try
{
resources = clr.getResources(location, cls != null ? cls.getClassLoader() : null);
}
catch (IOException e)
{
throw new JPOXException("Error loading resources", e).setFatal();
}
while (resources.hasMoreElements())
{
URL fileURL = (URL) resources.nextElement();
if (fileMetaDataByURLString.get(fileURL.toString()) == null)
{
// File hasn't been loaded so load it
FileMetaData filemd = parseFile(fileURL);
registerFile(fileURL.toString(), filemd, clr);
// Populate all classes in this file we've just parsed
// TODO Populate the classes found in this file
}
}
qmd = (QueryMetaData)queryMetaDataByName.get(query_key);
if (qmd != null)
{
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044053",query_key,location));
}
return qmd;
}
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044050",query_key,location));
}
}
return null;
}
/**
* Accessor for the MetaData for a Sequence in a package.
* If the sequence is not yet known will search the valid locations for the passed name.
* @param clr the ClassLoaderResolver
* @param packageSequenceName Fully qualified name of the sequence (inc package name)
* @return The SequenceMetaData for this named sequence
**/
public SequenceMetaData getMetaDataForSequence(ClassLoaderResolver clr, String packageSequenceName)
{
SequenceMetaData seqmd = super.getMetaDataForSequence(clr, packageSequenceName);
if (seqmd != null)
{
return seqmd;
}
// MetaData not found so maybe just not yet loaded
String packageName = packageSequenceName;
if (packageSequenceName.lastIndexOf('.') >= 0)
{
packageName = packageSequenceName.substring(0, packageSequenceName.lastIndexOf('.'));
}
// Search valid JDO file locations ("jdo" and "orm" files for the specified package)
List locations = new ArrayList();
locations.addAll(getValidMetaDataLocationsForItem(getJDOFileSuffix(), null, packageName, false));
locations.addAll(getValidMetaDataLocationsForItem(getORMFileSuffix(), getORMMappingName(), packageName, false));
for (int i=0; i<locations.size(); i++)
{
String location = (String) locations.get(i);
// Process all resources for this location
Enumeration resources;
try
{
resources = clr.getResources(location, null);
}
catch (IOException e)
{
throw new JPOXException("Error loading resource", e).setFatal();
}
while (resources.hasMoreElements())
{
URL fileURL = (URL) resources.nextElement();
if (fileMetaDataByURLString.get(fileURL.toString()) == null)
{
// File hasn't been loaded so load it
FileMetaData filemd = parseFile(fileURL);
registerFile(fileURL.toString(), filemd, clr);
// Populate all classes in this file we've just parsed
// TODO Populate the classes found in this file
}
}
seqmd = (SequenceMetaData)sequenceMetaDataByPackageSequence.get(packageSequenceName);
if (seqmd != null)
{
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044053", packageSequenceName, location));
}
return seqmd;
}
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044051", packageSequenceName, location));
}
}
return null;
}
/**
* Load up and add the O/R mapping info for the specified class to the stored JDO ClassMetaData.
* @param c The class
* @param clr the ClassLoaderResolver
*/
public void addORMDataToClass(Class c, ClassLoaderResolver clr)
{
if (enhancing)
{
// We don't need ORM data when enhancing
return;
}
if (!supportsORM)
{
// StoreManager doesnt "map" to the datastore so don't use ORM info
return;
}
// Get the JDO MetaData for this class/interface
AbstractClassMetaData cmd = (AbstractClassMetaData)classMetaDataByClass.get(c.getName());
// See if we already have a file registered with the ORM metadata for this class
AbstractClassMetaData ormCmd = (AbstractClassMetaData)ormClassMetaDataByClass.get(c.getName());
if (ormCmd != null)
{
// Merge the ORM class into the JDO class
MetaDataMerger.mergeClassORMData(cmd, ormCmd);
// Remove it from the map since no longer needed
ormClassMetaDataByClass.remove(c.getName());
return;
}
// No ORM loaded for this class, so find if there is any ORM metadata available
FileMetaData filemdORM = loadMetaDataForClass(c, clr, getORMMappingName(), getORMFileSuffix(), false);
if (filemdORM != null)
{
// The ORM file has now been registered, so find the class and merge it into the JDO definition
ormCmd = (AbstractClassMetaData)ormClassMetaDataByClass.get(c.getName());
if (ormCmd != null)
{
// Merge the ORM file into the JDO file
MetaDataMerger.mergeFileORMData((FileMetaData)cmd.getPackageMetaData().getParent(),
(FileMetaData)ormCmd.getPackageMetaData().getParent());
// Merge the ORM class into the JDO class
MetaDataMerger.mergeClassORMData(cmd, ormCmd);
// Remove it from the map since no longer needed
ormClassMetaDataByClass.remove(c.getName());
}
}
}
/**
* Method to find the Meta-Data file for a specified class.
* Checks the locations one-by-one, and checks for existence of the
* specified class in the file. If a valid file is found it is loaded no matter
* if the file contains the actual class. When a file is found containing the class
* the process stops and the FileMetaData for that file (containing the class) returned.
* <P>
* Allows 2 variations on the naming above. The first is a modifier which
* caters for a JDO 2.0 requirement whereby the user can specify a modifier
* such as "mysql", which would mean that this should search for filenames
* "package-mysql.jdo". The second variation is the suffix of the file.
* This is "jdo" by default, but JDO 2.0 has situations where "orm", or
* "jdoquery" are required as a suffix.
* </P>
* @param pc_class The class/interface to retrieve the Meta-Data file for
* @param clr the ClassLoaderResolver
* @param metadata_file_modifier Any modifier for the filename
* @param metadata_file_extension File extension of MetaData files (e.g "jdo")
* @param populate Whether to populate any loaded MetaData classes
* @return FileMetaData for the file containing the class
**/
protected FileMetaData loadMetaDataForClass(Class pc_class,
ClassLoaderResolver clr,
String metadata_file_modifier,
String metadata_file_extension,
boolean populate)
{
// MetaData file locations
List validLocations = getValidMetaDataLocationsForClass(metadata_file_extension, metadata_file_modifier, pc_class.getName());
Iterator locationsIter = validLocations.iterator();
while (locationsIter.hasNext())
{
String location = (String)locationsIter.next();
Enumeration resources;
try
{
resources = clr.getResources(location, pc_class.getClassLoader());
}
catch (IOException e)
{
throw new JPOXException("Error loading resource", e).setFatal();
}
if (!resources.hasMoreElements() && JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044049",
metadata_file_extension, pc_class.getName(), location));
}
while (resources.hasMoreElements())
{
URL url = (URL) resources.nextElement();
if (url != null)
{
// File exists (valid URL), so check if we already have this file registered
FileMetaData filemd = (FileMetaData)fileMetaDataByURLString.get(url.toString());
if (filemd == null)
{
// Not registered so load the file from the URL
filemd = parseFile(url);
registerFile(url.toString(), filemd, clr);
if (populate)
{
// Populate all classes in this file we've just parsed
populateFileMetaData(filemd, clr, pc_class.getClassLoader());
}
}
if ((filemd.getType() == FileMetaData.JDO_FILE && classMetaDataByClass.get(pc_class.getName()) != null) ||
(filemd.getType() == FileMetaData.ORM_FILE && ormClassMetaDataByClass.get(pc_class.getName()) != null))
{
// We now have the class, so it must have been in this file
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044052", metadata_file_extension, pc_class.getName(), url));
}
return filemd;
}
}
}
}
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044048", metadata_file_extension, pc_class.getName()));
}
return null;
}
/**
* Method to return the valid metadata locations to contain a particular package.
* @param fileExtension File extension (e.g "jdo")
* @param fileModifier Any modifier (for use when using ORM files package-mysql.orm, this is the "mysql" part)
* @param packageName The package name to look for
* @return The list of valid locations
*/
public List getValidMetaDataLocationsForPackage(String fileExtension, String fileModifier, String packageName)
{
return getValidMetaDataLocationsForItem(fileExtension, fileModifier, packageName, false);
}
/**
* Method to return the valid metadata locations to contain a particular class.
* @param fileExtension File extension (e.g "jdo")
* @param fileModifier Any modifier (for use when using ORM files package-mysql.orm, this is the "mysql" part)
* @param className The class name to look for
* @return The list of valid locations
*/
public List getValidMetaDataLocationsForClass(String fileExtension, String fileModifier, String className)
{
return getValidMetaDataLocationsForItem(fileExtension, fileModifier, className, true);
}
// Parameters used in the definition of MetaData file location
private static final char CLASS_SEPARATOR = '.';
private static final char PATH_SEPARATOR = '/';
private static final char EXTENSION_SEPARATOR = '.';
private static final String METADATA_PACKAGE = "package";
private static final String METADATA_LOCATION_METAINF = "/META-INF/" + METADATA_PACKAGE;
private static final String METADATA_LOCATION_WEBINF = "/WEB-INF/" + METADATA_PACKAGE;
/**
* Method to return the valid metadata locations to contain a particular item. The
* "item" can be a package or a class. Will look in the locations appropriate for the
* setting of "locationDefintion".
* @param fileExtension File extension (e.g "jdo") accepts comma separated list
* @param fileModifier Any modifier (for use when using ORM files package-mysql.orm, this is the "mysql" part)
* @param itemName The name of the item (package or class)
* @param isClass Whether this is a class
* @return The list of valid locations
*/
List getValidMetaDataLocationsForItem(String fileExtension, String fileModifier, String itemName, boolean isClass)
{
// Build up a list of valid locations
List locations = new ArrayList();
if (fileExtension == null)
{
fileExtension = "jdo";
}
StringTokenizer tokens = new StringTokenizer(fileExtension,",");
while( tokens.hasMoreTokens() )
{
locations.addAll(getValidMetaDataLocationsForSingleExtension(tokens.nextToken(),fileModifier,itemName,isClass));
}
return locations;
}
/**
* Method to return the valid metadata locations to contain a particular item. The
* "item" can be a package or a class. Will look in the locations appropriate for the
* setting of "locationDefintion".
* @param fileExtension File extension (e.g "jdo")
* @param fileModifier Any modifier (for use when using ORM files package-mysql.orm, this is the "mysql" part)
* @param itemName The name of the item (package or class)
* @param isClass Whether this is a class
* @return The list of valid locations
*/
private List getValidMetaDataLocationsForSingleExtension(String fileExtension, String fileModifier, String itemName, boolean isClass)
{
// Build up a list of valid locations
List locations = new ArrayList();
String suffix = null;
if (fileExtension == null)
{
fileExtension = "jdo";
}
if (fileModifier != null)
{
// This will be something like "-mysql.orm" (suffix for ORM files)
suffix = "-" + fileModifier + EXTENSION_SEPARATOR + fileExtension;
}
else
{
suffix = EXTENSION_SEPARATOR + fileExtension;
}
if (locationDefinition == ALL_JDO_LOCATIONS || locationDefinition == JDO_1_0_1_LOCATIONS)
{
locations.add((METADATA_LOCATION_METAINF + suffix)); // "/META-INF/package.jdo" (JDO 1.0.1)
locations.add((METADATA_LOCATION_WEBINF + suffix)); // "/WEB-INF/package.jdo" (JDO 1.0.1)
locations.add(PATH_SEPARATOR + METADATA_PACKAGE + suffix); // "/package.jdo" (JDO 1.0.1)
}
if (itemName != null && itemName.length() > 0)
{
int separatorPosition = itemName.indexOf('.');
if (separatorPosition < 0)
{
if (locationDefinition == ALL_JDO_LOCATIONS || locationDefinition == JDO_1_0_1_LOCATIONS)
{
// "/com/package.jdo" (JDO 1.0.1)
locations.add(PATH_SEPARATOR + itemName + PATH_SEPARATOR + METADATA_PACKAGE + suffix);
}
if (locationDefinition == ALL_JDO_LOCATIONS || locationDefinition == JDO_1_0_0_LOCATIONS)
{
// "/com.jdo" (JDO 1.0.0)
locations.add(PATH_SEPARATOR + itemName + suffix);
}
}
else
{
while (separatorPosition >= 0)
{
String name = itemName.substring(0, separatorPosition);
if (locationDefinition == ALL_JDO_LOCATIONS || locationDefinition == JDO_1_0_1_LOCATIONS)
{
// "/com/xyz/package.jdo" (JDO 1.0.1)
locations.add(PATH_SEPARATOR + name.replace(CLASS_SEPARATOR, PATH_SEPARATOR) + PATH_SEPARATOR + METADATA_PACKAGE + suffix);
}
if (locationDefinition == ALL_JDO_LOCATIONS || locationDefinition == JDO_1_0_0_LOCATIONS)
{
// "/com/xyz.jdo" (JDO 1.0.0)
locations.add(PATH_SEPARATOR + name.replace(CLASS_SEPARATOR, PATH_SEPARATOR) + suffix);
}
separatorPosition = itemName.indexOf('.', separatorPosition+1);
if (separatorPosition < 0)
{
if (!isClass)
{
if (locationDefinition == ALL_JDO_LOCATIONS || locationDefinition == JDO_1_0_1_LOCATIONS)
{
// "/com/xyz/uvw/package.jdo" (JDO 1.0.1)
locations.add(PATH_SEPARATOR + itemName.replace(CLASS_SEPARATOR, PATH_SEPARATOR) + PATH_SEPARATOR + METADATA_PACKAGE + suffix);
}
}
if (locationDefinition == ALL_JDO_LOCATIONS || locationDefinition == JDO_1_0_0_LOCATIONS)
{
// "/com/xyz/uvw.jdo" (JDO 1.0.0)
locations.add(PATH_SEPARATOR + itemName.replace(CLASS_SEPARATOR, PATH_SEPARATOR) + suffix);
}
}
}
}
}
return locations;
}
// ------------------------------- Persistent Interfaces ---------------------------------------
/**
* Main accessor for the MetaData for a "persistent-interface".
* All MetaData returned from this method will be initialised and ready for full use.
* @param c The interface to find MetaData for
* @param clr the ClassLoaderResolver
* @return The InterfaceMetaData for this interface (or null if not found)
*/
public InterfaceMetaData getMetaDataForInterface(Class c, ClassLoaderResolver clr)
{
if (c == null || !c.isInterface())
{
return null;
}
InterfaceMetaData imd = (InterfaceMetaData)getMetaDataForClassInternal(c, clr);
if (imd != null)
{
// Make sure that anything returned is initialised
if (!imd.isPopulated() && !imd.isInitialised())
{
// Initialise the interface in question
imd.populate(clr,c.getClassLoader());
}
// Make sure that anything returned is initialised
if (!imd.isInitialised())
{
// Initialise the interface in question
imd.initialise();
}
if (utilisedFileMetaData.size() > 0)
{
// Initialise all FileMetaData that were processed in this call
Iterator iter = utilisedFileMetaData.iterator();
while (iter.hasNext())
{
FileMetaData filemd = (FileMetaData)iter.next();
initialiseFileMetaData(filemd, clr, c.getClassLoader());
}
}
}
utilisedFileMetaData.clear();
return imd;
}
/**
* Convenience method to return if the passed class name is a "persistent-interface".
* @param name Name if the interface
* @return Whether it is a "persistent-interface"
*/
public boolean isPersistentInterface(String name)
{
// Find if this class has <interface> metadata
AbstractClassMetaData acmd = (AbstractClassMetaData)classMetaDataByClass.get(name);
return (acmd != null && acmd instanceof InterfaceMetaData);
}
/**
* Convenience method to return if the passed class name is an implementation of the passed "persistent-interface".
* @param interfaceName Name of the persistent interface
* @param implName The implementation name
* @return Whether it is a (JPOX-generated) impl of the persistent interface
*/
public boolean isPersistentInterfaceImplementation(String interfaceName, String implName)
{
ClassMetaData cmd = (ClassMetaData)classMetaDataByInterface.get(interfaceName);
return (cmd != null && cmd.getFullClassName().equals(implName));
}
/**
* Convenience method to return if the passed class name is an implementation of a "persistent definition".
* @param implName The implementation name
* @return Whether it is a (JPOX-generated) impl of the persistent interface or abstract class
*/
public boolean isPersistentDefinitionImplementation(String implName)
{
ClassMetaData cmd = (ClassMetaData)classMetaDataByClass.get(implName);
return (cmd != null && cmd.isImplementationOfPersistentDefinition());
}
/**
* Accessor for the implementation name for the specified "persistent-interface".
* @param interfaceName The name of the persistent interface
* @return The name of the implementation class
*/
public String getImplementationNameForPersistentInterface(String interfaceName)
{
ClassMetaData cmd = (ClassMetaData)classMetaDataByInterface.get(interfaceName);
return (cmd != null ? cmd.getFullClassName() : null);
}
/**
* Accessor for the metadata for the implementation of the specified "persistent-interface".
* @param interfaceName The name of the persistent interface
* @return The ClassMetaData of the implementation class
*/
public ClassMetaData getClassMetaDataForImplementationOfPersistentInterface(String interfaceName)
{
return (ClassMetaData)classMetaDataByInterface.get(interfaceName);
}
/**
* Method to register a persistent interface and its implementation with the MetaData system.
* @param imd MetaData for the interface
* @param implClass The implementation class
* @param clr ClassLoader Resolver to use
*/
public void registerPersistentInterface(InterfaceMetaData imd, Class implClass, ClassLoaderResolver clr)
{
// Create ClassMetaData for the implementation
ClassMetaData cmd = new ClassMetaData(imd, implClass.getName(), true);
cmd.addImplements(new ImplementsMetaData(cmd,imd.getFullClassName()));
// Register the ClassMetaData for the implementation
registerMetaDataForClass(cmd.getFullClassName(), cmd);
// Register the metadata for the implementation against this persistent interface
classMetaDataByInterface.put(imd.getFullClassName(), cmd);
initialiseClassMetaData(cmd, implClass, clr);
// Deregister the metadata for the implementation from those "not found"
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044044",implClass.getName()));
}
classesWithoutPersistenceInfo.remove(implClass.getName());
}
/**
* Method to register the metadata for an implementation of a persistent abstract class.
* @param cmd MetaData for the abstract class
* @param implClass The implementation class
* @param clr ClassLoader resolver
*/
public void registerImplementationOfAbstractClass(ClassMetaData cmd, Class implClass, ClassLoaderResolver clr)
{
ClassMetaData implCmd = new ClassMetaData(cmd, implClass.getName());
// Register the ClassMetaData for the implementation
registerMetaDataForClass(implCmd.getFullClassName(), implCmd);
initialiseClassMetaData(implCmd, implClass, clr);
// Deregister the metadata for the implementation from those "not found"
if (JPOXLogger.METADATA.isDebugEnabled())
{
JPOXLogger.METADATA.debug(LOCALISER.msg("044044", implClass.getName()));
}
classesWithoutPersistenceInfo.remove(implClass.getName());
}
}