You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ar...@apache.org on 2003/05/24 02:56:38 UTC
cvs commit: db-ojb/src/java/org/apache/ojb/broker/metadata MetadataManager.java
arminw 2003/05/23 17:56:38
Modified: src/test/org/apache/ojb/broker/metadata MetadataTest.java
src/java/org/apache/ojb/broker/metadata MetadataManager.java
Log:
add some new methods, tests, doc
Revision Changes Path
1.8 +78 -12 db-ojb/src/test/org/apache/ojb/broker/metadata/MetadataTest.java
Index: MetadataTest.java
===================================================================
RCS file: /home/cvs/db-ojb/src/test/org/apache/ojb/broker/metadata/MetadataTest.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- MetadataTest.java 22 May 2003 19:39:42 -0000 1.7
+++ MetadataTest.java 24 May 2003 00:56:38 -0000 1.8
@@ -5,6 +5,8 @@
import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.PersistenceBrokerFactory;
import org.apache.ojb.broker.TestHelper;
+import org.apache.ojb.broker.Identity;
+import org.apache.ojb.broker.PersistenceBrokerException;
import org.apache.ojb.broker.query.Criteria;
import org.apache.ojb.broker.query.Query;
import org.apache.ojb.broker.query.QueryFactory;
@@ -39,29 +41,93 @@
junit.textui.TestRunner.main(arr);
}
- /**
- * Insert the method's description here.
- * Creation date: (24.12.2000 00:33:40)
- */
public MetadataTest(String name)
{
super(name);
}
- /**
- * Insert the method's description here.
- * Creation date: (06.12.2000 21:58:53)
- */
public void setUp()
{
}
- /**
- * Insert the method's description here.
- * Creation date: (06.12.2000 21:59:14)
- */
public void tearDown()
{
+
+ }
+
+ public void testLoadingProfiles() throws Exception
+ {
+ PersistenceBroker broker = null;
+ MetadataManager mm = MetadataManager.getInstance();
+ try
+ {
+ mm.setEnablePerThreadChanges(true);
+ DescriptorRepository dr_1 = mm.readDescriptorRepository(TEST_CLASS_DESCRIPTOR);
+ // add some profiles
+ mm.addProfile("global", mm.getGlobalRepository());
+ mm.addProfile("test", dr_1);
+
+ // now load a specific profile
+ mm.loadProfile("test");
+ broker = PersistenceBrokerFactory.defaultPersistenceBroker();
+ CldTestObject obj = new CldTestObject();
+ obj.setName("testLoadingProfiles");
+ try
+ {
+ broker.store(obj);
+ try
+ {
+ // try to find persistent object, only available in global
+ // repository profile
+ Class clazz = broker.getClassDescriptor(testClass).getClassOfObject();
+ fail("We should not found this class-descriptor in profile");
+ }
+ catch (PersistenceBrokerException e)
+ {
+ }
+ }
+ finally
+ {
+ broker.close();
+ }
+
+ //***************************************
+ mm.removeProfile("test");
+ try
+ {
+ mm.loadProfile("test");
+ fail("Loading of profile should fail, but doesn't");
+ }
+ catch (Exception e)
+ {
+ }
+ // now we load copy of global DescriptorRepository
+ mm.loadProfile("global");
+ broker = PersistenceBrokerFactory.defaultPersistenceBroker();
+ Class clazz = broker.getClassDescriptor(testClass).getClassOfObject();
+ broker.close();
+ assertEquals(testClass, clazz);
+ mm.removeAllProfiles();
+ try
+ {
+ mm.loadProfile("global");
+ fail("Loading of profile should fail, but doesn't");
+ }
+ catch (Exception e)
+ {
+ }
+
+ broker = PersistenceBrokerFactory.defaultPersistenceBroker();
+ clazz = broker.getClassDescriptor(testClass).getClassOfObject();
+ broker.close();
+ assertEquals(testClass, clazz);
+ }
+ finally
+ {
+ mm.setEnablePerThreadChanges(false);
+ if(broker != null) broker.close();
+ }
+
}
1.10 +224 -56 db-ojb/src/java/org/apache/ojb/broker/metadata/MetadataManager.java
Index: MetadataManager.java
===================================================================
RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/metadata/MetadataManager.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- MetadataManager.java 26 Apr 2003 23:18:24 -0000 1.9
+++ MetadataManager.java 24 May 2003 00:56:38 -0000 1.10
@@ -1,58 +1,100 @@
package org.apache.ojb.broker.metadata;
-import java.util.Iterator;
-import java.util.List;
-
import org.apache.commons.lang.SerializationUtils;
import org.apache.ojb.broker.core.PersistenceBrokerConfiguration;
import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;
+import java.io.InputStream;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+
/**
- * Central class for metadata operations - manages all OJB's
- * {@link org.apache.ojb.broker.metadata.DescriptorRepository} and
- * {@link org.apache.ojb.broker.metadata.ConnectionRepository} instances.
- * <br>
- * Allow a bunch of different repository handling possibilities -
- * allows a transparent flexible metadata manipulation at runtime.
- * <p>
+ * Central class for metadata operations/manipulations - manages OJB's
+ * metadata objects, in particular:
+ * <ul>
+ * <li>{@link org.apache.ojb.broker.metadata.DescriptorRepository} contains
+ * metadata of persistent objects</li>
+ * <li>{@link org.apache.ojb.broker.metadata.ConnectionRepository} contains
+ * all connection metadata information</li>
+ * </ul>
*
+ * This class allows transparent flexible metadata loading/manipulation at runtime.
*
- * TODO: Is this a really useful feature?
+ * <p>
+ * <b>How to read/merge metadata</b><br/>
+ * Per default OJB loads default {@link org.apache.ojb.broker.metadata.DescriptorRepository}
+ * and {@link org.apache.ojb.broker.metadata.ConnectionRepository} instances, by reading the
+ * specified repository file. This is done first time the <code>MetadataManager</code> instance
+ * was used.
+ * <br/>
+ * To read metadata information at runtime use
+ * {@link #readDescriptorRepository readDescriptorRepository} and
+ * {@link #readConnectionRepository readConnectionRepository}
+ * methods.
+ * <br/>
+ * It is also possible to merge different repositories using
+ * {@link #mergeDescriptorRepository mergeDescriptorRepository}
+ * and {@link #mergeConnectionRepository mergeConnectionRepository}
*
+ * </p>
*
* <a name="perThread"/>
- * <b>Per thread handling of metadata</b>
- * <br/>
+ * <h3>Per thread handling of metadata</h3>
+ * <p>
* Per default the manager handle one global {@link org.apache.ojb.broker.metadata.DescriptorRepository}
- * for all calling threads, but it is ditto possible to change metadata only per thread. When the thread
- * dies all made changes were rejected.
- * <br/>
- * To use this feature do something similar:
+ * for all calling threads, but it is ditto possible to use different metadata <i>profiles</i> in a per thread
+ * manner - <i>profiles</i> means different copies of {@link org.apache.ojb.broker.metadata.DescriptorRepository}
+ * objects.
+ * <p/>
+ *
+ * <p>
+ * <a name="enablePerThreadMode"/>
+ * <b>Enable the per thread mode</b><br/>
+ * To enable the 'per thread' mode for {@link org.apache.ojb.broker.metadata.DescriptorRepository}
+ * instances:
* <pre>
* MetadataManager mm = MetadataManager.getInstance();
* // tell the manager to use per thread mode
* mm.setEnablePerThreadChanges(true);
- *
+ * ...
+ * </pre>
+ * This could be done e.g. at start up.<br/>
+ * Now it's possible to use dedicated <code>DescriptorRepository</code> instances
+ * per thread:
+ * <pre>
* // e.g we get a coppy of the global repository
* DescriptorRepository dr = mm.copyOfGlobalRepository();
- * // now we can manipulate the metadata of the copy
+ * // now we can manipulate the persistent object metadata of the copy
* ......
*
* // set the changed repository for this thread
- * mm.setPerThreadDescriptor(dr);
+ * mm.setDescriptor(dr);
*
- * // now this thread could lookup a PB with the modified metadata
+ * // now this thread could lookup a PersistenceBroker instance
+ * // with the modified metadata
* // all other threads use the global metadata
* PersistenceBroker broker = Persis......
* </pre>
- * First do {@link #setEnablePerThreadChanges enable the per thread mode}
- * handling. This could be done e.g. at setup. Now each thread could use
- * its own metadata, but you have
- * <br/>a) explicit to set the new repository per thread
- * <br/>b) do this BEFORE you lookup the {@link PersistenceBroker} for
- * the thread, because the metadata was bound to the PB at lookup.
+ * Note: Change metadata <i>before</i> lookup the {@link org.apache.ojb.broker.PersistenceBroker}
+ * instance for current thread, because the metadata was bound to the PB at lookup.
+ * </p>
+ *
+ * <p>
+ * <b>How to use different metadata profiles</b><br/>
+ * MetadataManager was shipped with a simple mechanism to
+ * add, remove and load different persistent objects metadata
+ * profiles (different {@link org.apache.ojb.broker.metadata.DescriptorRepository}
+ * instances) in a per thread manner. Use
+ * <ul>
+ * <li>{@link #addProfile addProfile} add different persistent object metadata profiles</li>
+ * <li>{@link #removeProfile removeProfile} remove a persistent object metadata profiles</li>
+ * <li>{@link #loadProfile loadProfile} load a profile for the current thread</li>
+ * </ul>
+ * Note: This only works if the <a href="#enablePerThreadMode">per thread mode</a> is
+ * enabled.
* </p>
*
*
@@ -66,6 +108,7 @@
private static ThreadLocal threadedRepository = new ThreadLocal();
private static MetadataManager singleton = new MetadataManager();
+ private Hashtable metadataProfiles;
private DescriptorRepository globalRepository;
private ConnectionRepository connectionRepository;
private boolean enablePerThreadChanges;
@@ -78,8 +121,9 @@
private void init()
{
+ metadataProfiles = new Hashtable();
String repository = ((PersistenceBrokerConfiguration) OjbConfigurator.getInstance()
- .getConfigurationFor(null)).getRepositoryFilename();
+ .getConfigurationFor(null)).getRepositoryFilename();
try
{
globalRepository = new RepositoryPersistor().readDescriptorRepository(repository);
@@ -87,7 +131,7 @@
catch (Exception e)
{
throw new MetadataException(
- "Could not read repository class descriptor data, using repository: "+repository,e);
+ "Could not read repository class descriptor data, using repository: " + repository, e);
}
try
{
@@ -96,7 +140,7 @@
catch (Exception e)
{
throw new MetadataException(
- "Could not read jdbc-connection-descriptor data, using repository: "+repository,e);
+ "Could not read jdbc-connection-descriptor data, using repository: " + repository, e);
}
}
@@ -114,8 +158,8 @@
* {@link org.apache.ojb.broker.metadata.DescriptorRepository}.
* <br>
* When {@link #isEnablePerThreadChanges per thread descriptor handling} is enabled
- * we first search for a {@link org.apache.ojb.broker.metadata.DescriptorRepository}
- * for the calling thread, if not found the global descriptor was returned.
+ * we first search for a specific {@link org.apache.ojb.broker.metadata.DescriptorRepository}
+ * for the calling thread, if none could be found the global descriptor was returned.
*
* @see MetadataManager#getGlobalRepository
* @see MetadataManager#copyOfGlobalRepository
@@ -126,11 +170,9 @@
if (enablePerThreadChanges)
{
repository = (DescriptorRepository) threadedRepository.get();
- if(repository == null)
+ if (repository == null)
{
repository = getGlobalRepository();
-// repository = copyOfGlobalRepository();
-// threadedRepository.set(repository);
}
return repository;
}
@@ -161,23 +203,40 @@
}
/**
- * Merge the given {@link ConnectionRepository} with the
- * existing one.
+ * Merge the given {@link ConnectionRepository} (make deep copy of containing objects)
+ * with the existing one.
*/
public void mergeConnectionRepository(ConnectionRepository repository)
{
- List list = repository.getAllDescriptor();
+ mergeConnectionRepository(connectionRepository(), repository, true);
+ }
+
+ /**
+ * Merge the given source {@link ConnectionRepository} with the
+ * existing target. If parameter
+ * <tt>deep</tt> is set <code>true</code> deep copies of source objects were made.
+ */
+ public void mergeConnectionRepository(
+ ConnectionRepository targetRepository, ConnectionRepository sourceRepository, boolean deep)
+ {
+ List list = sourceRepository.getAllDescriptor();
for (Iterator iterator = list.iterator(); iterator.hasNext();)
{
JdbcConnectionDescriptor jcd = (JdbcConnectionDescriptor) iterator.next();
- connectionRepository().addDescriptor(jcd);
+ if (deep)
+ {
+ //TODO: adopt copy/clone methods for metadata classes?
+ jcd = (JdbcConnectionDescriptor) SerializationUtils.clone(jcd);
+ }
+ targetRepository.addDescriptor(jcd);
}
}
/**
* Merge the given {@link org.apache.ojb.broker.metadata.DescriptorRepository}
- * with the existing one - keep in mind if running in
- * <a href="#perThread">per thread mode</a>
+ * (make deep copy of containing objects) with the global one, returned
+ * by method {@link #getRepository()} - keep
+ * in mind if running in <a href="#perThread">per thread mode</a>
* merge maybe only takes effect on current thread.
*
* @see #isEnablePerThreadChanges
@@ -185,18 +244,33 @@
*/
public void mergeDescriptorRepository(DescriptorRepository repository)
{
- DescriptorRepository targetRepository = getRepository();
- Iterator it = repository.iterator();
+ mergeDescriptorRepository(getRepository(), repository, true);
+ }
+
+ /**
+ * Merge the given {@link org.apache.ojb.broker.metadata.DescriptorRepository}
+ * files, the source objects will be pushed to the target repository. If parameter
+ * <tt>deep</tt> is set <code>true</code> deep copies of source objects were made.
+ */
+ public void mergeDescriptorRepository(
+ DescriptorRepository targetRepository, DescriptorRepository sourceRepository, boolean deep)
+ {
+ Iterator it = sourceRepository.iterator();
while (it.hasNext())
{
ClassDescriptor cld = (ClassDescriptor) it.next();
- cld.setRepository(targetRepository);
+ if (deep)
+ {
+ //TODO: adopt copy/clone methods for metadata classes?
+ cld = (ClassDescriptor) SerializationUtils.clone(cld);
+ }
targetRepository.put(cld.getClassOfObject(), cld);
+ cld.setRepository(targetRepository);
}
}
/**
- * Read all ClassDescriptors from the given repository file.
+ * Read ClassDescriptors from the given repository file.
* @see #mergeDescriptorRepository
*/
public DescriptorRepository readDescriptorRepository(String fileName)
@@ -208,14 +282,32 @@
}
catch (Exception e)
{
- throw new MetadataException("Could not read repository "+fileName, e);
+ throw new MetadataException("Could not read repository " + fileName, e);
}
}
- /**
- * Read all JdbcConnectionDescriptors from the given repository file.
- * @see #mergeConnectionRepository
- */
+ /**
+ * Read ClassDescriptors from the given InputStream.
+ * @see #mergeDescriptorRepository
+ */
+ public DescriptorRepository readDescriptorRepository(InputStream inst)
+ {
+ try
+ {
+ RepositoryPersistor persistor = new RepositoryPersistor();
+ return persistor.readDescriptorRepository(inst);
+ }
+ catch (Exception e)
+ {
+ throw new MetadataException("Could not read repository " + inst, e);
+ }
+ }
+
+ /**
+ * Read JdbcConnectionDescriptors from the given repository file.
+ *
+ * @see #mergeConnectionRepository
+ */
public ConnectionRepository readConnectionRepository(String fileName)
{
try
@@ -225,7 +317,25 @@
}
catch (Exception e)
{
- throw new MetadataException("Could not read repository "+fileName, e);
+ throw new MetadataException("Could not read repository " + fileName, e);
+ }
+ }
+
+ /**
+ * Read JdbcConnectionDescriptors from this InputStream.
+ *
+ * @see #mergeConnectionRepository
+ */
+ public ConnectionRepository readConnectionRepository(InputStream inst)
+ {
+ try
+ {
+ RepositoryPersistor persistor = new RepositoryPersistor();
+ return persistor.readConnectionRepository(inst);
+ }
+ catch (Exception e)
+ {
+ throw new MetadataException("Could not read repository from " + inst, e);
}
}
@@ -239,21 +349,32 @@
*/
public void setDescriptor(DescriptorRepository repository, boolean global)
{
- if(global)
+ if (global)
{
- if(log.isDebugEnabled()) log.debug("Set new global repository: "+repository);
+ if (log.isDebugEnabled()) log.debug("Set new global repository: " + repository);
globalRepository = repository;
}
else
{
- if(log.isDebugEnabled()) log.debug("Set new threaded repository: "+repository);
+ if (log.isDebugEnabled()) log.debug("Set new threaded repository: " + repository);
threadedRepository.set(repository);
}
}
/**
+ * Set {@link DescriptorRepository} for the current thread.
+ * Convenience method for
+ * {@link #setDescriptor(DescriptorRepository repository, boolean global) setDescriptor(repository, false)}.
+ */
+ public void setDescriptor(DescriptorRepository repository)
+ {
+ setDescriptor(repository, false);
+ }
+
+ /**
* Convenience method for
* {@link #setDescriptor setDescriptor(repository, false)}.
+ * @deprecated use {@link #setDescriptor}
*/
public void setPerThreadDescriptor(DescriptorRepository repository)
{
@@ -279,7 +400,7 @@
* repository file if set, or the global if no threaded was found.
* <br>
* If returns <i>false</i> the {@link #getRepository} method return
- * always the {@link getGlobalRepository global} repository.
+ * always the {@link #getGlobalRepository() global} repository.
*
* @see #setEnablePerThreadChanges
*/
@@ -299,8 +420,55 @@
this.enablePerThreadChanges = enablePerThreadChanges;
}
+ /**
+ * Add a metadata profile.
+ * @see #loadProfile
+ */
+ public void addProfile(Object key, DescriptorRepository repository)
+ {
+ if(metadataProfiles.contains(key))
+ {
+ throw new MetadataException("Duplicate profile key. Key '"+key+"' already exists.");
+ }
+ metadataProfiles.put(key, repository);
+ }
+
+ /**
+ * Load the given metadata profile for the current thread.
+ *
+ */
+ public void loadProfile(Object key)
+ {
+ if (!isEnablePerThreadChanges())
+ {
+ throw new MetadataException("Could not load profile with disabled per thread mode");
+ }
+ DescriptorRepository rep = (DescriptorRepository) metadataProfiles.get(key);
+ if (rep == null)
+ {
+ throw new MetadataException("Could not find profile for key '" + key+"'");
+ }
+ setDescriptor(rep);
+ }
+ /**
+ * Remove the given metadata profile.
+ */
+ public DescriptorRepository removeProfile(Object key)
+ {
+ return (DescriptorRepository) metadataProfiles.remove(key);
+ }
+ /**
+ * Remove all profiles
+ *
+ * @see #removeProfile
+ * @see #addProfile
+ */
+ public void removeAllProfiles()
+ {
+ metadataProfiles.clear();
+ }
// /**
// * Returns a new {@link ClassDescriptor} instance.