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 th...@apache.org on 2003/07/08 08:05:00 UTC
cvs commit: db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess PersistentFieldAutoProxyImpl.java
thma 2003/07/07 23:05:00
Added: src/java/org/apache/ojb/broker/metadata/fieldaccess
PersistentFieldAutoProxyImpl.java
Log:
add a fieldaccess strategy that can switch automatically to use different other strategies if needed
Revision Changes Path
1.1 db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess/PersistentFieldAutoProxyImpl.java
Index: PersistentFieldAutoProxyImpl.java
===================================================================
package org.apache.ojb.broker.metadata.fieldaccess;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache ObjectRelationalBridge" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.lang.reflect.Field;
import java.util.Map;
import org.apache.commons.collections.FastHashMap;
import org.apache.ojb.broker.metadata.MetadataException;
import org.apache.ojb.broker.util.ClassHelper;
import org.apache.ojb.broker.util.logging.LoggerFactory;
/**
* PeristentField implementation that attempts to detect the nature of
* the field it is persisting.
* <p>
* First checks to see if it is a Field, then Property, then DynaBean
* <p>
* It will match in that order.
*
* @author <a href="brian@frums.net">Brian McCallister</a>
* @version
*/
public class PersistentFieldAutoProxyImpl implements PersistentField
{
private PersistentField wrapped;
private static final Class PERSIST_FIELD = PersistentFieldDefaultImpl.class;
private static final Class PERSIST_PROPERTY = PersistentFieldPropertyImpl.class;
private static final Class PERSIST_DYNA = PersistentFieldDynaBeanImpl.class;
/**
* Contains additional maps with name to PersistentFactory implementation Class
* instances
*/
private static Map classToName = new FastHashMap();
/**
* Being nice to Class.newInstance() seems popular.
*/
public PersistentFieldAutoProxyImpl()
{
}
/**
* Constructor will examine the Class type to attempt to determine what
* type of attribute this is (field, property, or DynaProperty and
* wrap an instance of the correct PersistentField implementation
* for that field.
* <p>
* TODO: Improve error reporting. Really need to keep why
* each one failed and give it lump some to the
* user so that the user can figure out why the one
* which was supposed to work didn't
*/
public PersistentFieldAutoProxyImpl(Class type, String name)
{
if (this.tryLoadFromCache(type, name))
{
return;
}
/*
* this switches on a series of exceptions. Sadly, it is the only real way to detect
* which one works. The cache should manage things so this chain only need be called
* once per field. --Brian
*/
try
{
this.tryFieldImpl(type, name);
return;
}
catch (Exception e)
{ // we don't care yet
}
try
{
this.tryPropertyImpl(type, name);
return;
}
catch (Exception e1)
{ // We still don't care
}
// Only option left is for it to be a dynabean
try
{
this.tryDynaBeanImpl(type, name);
return;
}
catch (Exception e)
{ // Technically we care, but we are baout to throw an exception anyway
}
// We couldn't match anything, throw Exception
String message =
"No field, property, or DynaProperty can be found to match " + type.getName() + "." + name + "()";
LoggerFactory.getDefaultLogger().warn(message);
throw new MetadataException(message);
}
private void tryDynaBeanImpl(Class type, String name) throws Exception
{
Class[] types = { Class.class, String.class };
Object[] args = { type, name };
wrapped = (PersistentField) ClassHelper.newInstance(PERSIST_DYNA, types, args);
}
private void tryPropertyImpl(Class type, String name) throws Exception
{
BeanInfo info = Introspector.getBeanInfo(type);
Class[] types = { Class.class, String.class };
Object[] args = { type, name };
wrapped = (PersistentField) ClassHelper.newInstance(PERSIST_PROPERTY, types, args);
}
/**
* If it finds an implementation in the cache it will load it into the
* wrapped field and return true.
*/
private boolean tryLoadFromCache(Class type, String name)
{
if (classToName.containsKey(name))
{
Map nameToImpl = (Map) classToName.get(name);
if (nameToImpl.containsKey(name))
{
Class[] types = { Class.class, String.class };
Object[] args = { type, name };
Class clazz = (Class) nameToImpl.get(type);
try
{
wrapped = (PersistentField) ClassHelper.newInstance(clazz, types, args);
}
catch (Exception e2)
{
LoggerFactory.getLogger(this.getClass()).warn(
"Unable to use cached PersistentField: " + clazz.getName(),
e2);
throw new MetadataException("Unable to use cached PersistentField: ", e2);
}
return true;
}
}
return false;
}
private void tryFieldImpl(Class type, String name) throws Exception
{
Field field = this.getFieldRecursive(type, name);
Class[] types = { Class.class, String.class };
Object[] args = { type, name };
wrapped = (PersistentField) ClassHelper.newInstance(PERSIST_FIELD, types, args);
}
/**
* REFACTOR: This is cut and paste code from PersistentFieldDefaultImpl,
*
* @throws NoSuchFieldException if no Field was found into the class hierarchy
*/
protected Field getFieldRecursive(Class c, String name) throws NoSuchFieldException
{
try
{
Field f = c.getDeclaredField(name);
return f;
}
catch (NoSuchFieldException e)
{
// if field could not be found in the inheritance hierarchy, signal error
if (c == Object.class)
{
throw e;
}
// if field could not be found in class c try in superclass
else
{
return getFieldRecursive(c.getSuperclass(), name);
}
}
}
private static synchronized void addToCache(Class type, String name, Class pfClass)
{
Map nameToImpl = null;
if (classToName.containsKey(type))
{
nameToImpl = (Map) classToName.get(type);
}
else
{
nameToImpl = new FastHashMap();
}
nameToImpl.put(name, pfClass);
}
/* These are all the implementation methods delagating to the wrapped impl*/
public Class getDeclaringClass()
{
return wrapped.getDeclaringClass();
}
public void set(Object obj, Object value) throws MetadataException
{
wrapped.set(obj, value);
}
public Object get(Object anObject) throws MetadataException
{
return wrapped.get(anObject);
}
public boolean usesAccessorsAndMutators()
{
return wrapped.usesAccessorsAndMutators();
}
public String getName()
{
return wrapped.getName();
}
public Class getType()
{
return wrapped.getType();
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org