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 2006/07/15 16:09:48 UTC
svn commit: r422225 [2/2] - in /db/ojb/trunk/src:
java/org/apache/ojb/broker/ java/org/apache/ojb/broker/accesslayer/
java/org/apache/ojb/broker/accesslayer/conversions/
java/org/apache/ojb/broker/metadata/
java/org/apache/ojb/broker/metadata/fieldacce...
Added: db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/fieldaccess/PersistentFieldCGLibImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/fieldaccess/PersistentFieldCGLibImpl.java?rev=422225&view=auto
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/fieldaccess/PersistentFieldCGLibImpl.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/fieldaccess/PersistentFieldCGLibImpl.java Sat Jul 15 07:09:47 2006
@@ -0,0 +1,244 @@
+package org.apache.ojb.broker.metadata.fieldaccess;
+
+/* Copyright 2003-2005 The Apache Software Foundation
+ *
+ * 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.
+ */
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.cglib.reflect.FastClass;
+import net.sf.cglib.reflect.FastMethod;
+import org.apache.commons.lang.StringUtils;
+import org.apache.ojb.broker.metadata.MetadataException;
+import org.apache.ojb.broker.util.ClassHelper;
+
+/**
+ * A {@link org.apache.ojb.broker.metadata.fieldaccess.PersistentField} implementation using
+ * JavaBeans compliant calls only to access persistent attributes.
+ * No Reflection is needed. But for each attribute xxx there must be
+ * public getXxx() and setXxx() methods. In metadata the field name must be
+ * the bean compliant 'xxx'.
+ *
+ * @version $Id: PersistentFieldIntrospectorImpl.java,v 1.11.2.2 2005/12/21 22:26:41 tomdz Exp $
+ */
+public final class PersistentFieldCGLibImpl extends PersistentFieldBase
+{
+ private Class type;
+ private transient FastMethod[] methodGraphGetter;
+ private transient FastMethod[] methodGraphSetter;
+ private transient FastMethod singleMethodGraphGetter;
+ private transient FastMethod singleMethodGraphSetter;
+ private transient boolean initialized;
+ private boolean nonNested = false;
+
+ public PersistentFieldCGLibImpl(Class aClass, String aPropertyName)
+ {
+ super(aClass, aPropertyName);
+ }
+
+ public Class getType()
+ {
+ if(type == null)
+ {
+ if(!initialized) init();
+ type = methodGraphGetter[methodGraphGetter.length - 1].getReturnType();
+ }
+ return type;
+ }
+
+ public void set(Object target, final Object value) throws MetadataException
+ {
+ if(target == null) return;
+ if(!initialized) init();
+
+ if(nonNested)
+ {
+ setValueFor(singleMethodGraphSetter, target, value);
+ }
+ else
+ {
+ int size = methodGraphSetter.length - 1;
+ for(int i = 0; i < size; i++)
+ {
+ Object attribute;
+ attribute = getValueFrom(methodGraphGetter[i], target);
+ if(attribute != null || value != null)
+ {
+ if(attribute == null)
+ {
+ try
+ {
+ attribute = ClassHelper.newInstance(methodGraphGetter[i].getReturnType());
+ }
+ catch(Exception e)
+ {
+ throw new MetadataException("Can't instantiate nested object of type '"
+ + methodGraphGetter[i].getReturnType() + "' for field '"
+ + methodGraphGetter[i].getName() + "'", e);
+ }
+ }
+ setValueFor(methodGraphSetter[i], target, attribute);
+ }
+ else
+ {
+ return;
+ }
+ target = attribute;
+ }
+ setValueFor(methodGraphSetter[size], target, value);
+ }
+ }
+
+ public Object get(Object target) throws MetadataException
+ {
+ if(!initialized) init();
+ if(nonNested)
+ {
+ return getValueFrom(singleMethodGraphGetter, target);
+ }
+ else
+ {
+ for(int i = 0; i < methodGraphGetter.length; i++)
+ {
+ FastMethod fastMethod = methodGraphGetter[i];
+ target = getValueFrom(fastMethod, target);
+ if(target == null) break;
+ }
+ return target;
+ }
+ }
+
+ private Object getValueFrom(final FastMethod fastMethodGetter, final Object target)
+ {
+ try
+ {
+ return fastMethodGetter.invoke(target, null);
+ }
+ catch(Throwable e)
+ {
+ String msg = buildGetterErrorMsg(fastMethodGetter.getReturnType(), target, "Can't read value from given object");
+ getLog().error(msg);
+ throw new MetadataException("Error invoking method:" + fastMethodGetter.getName() + " in object " + target.getClass().getName(), e);
+ }
+ }
+
+ private void setValueFor(final FastMethod fastMethodSetter, final Object target, Object value)
+ {
+ try
+ {
+ /**
+ * it is safe to call getParameterTypes()[0] because this is
+ * the "set" method and it needs to take one parameter only.
+ * we need to be able to set values to null. We can only set something to null if
+ * the type is not a primitive (assignable from Object).
+ */
+ if((value != null) || !fastMethodSetter.getParameterTypes()[0].isPrimitive())
+ {
+ fastMethodSetter.invoke(target, new Object[]{value});
+ }
+ }
+ catch(Throwable e)
+ {
+ Class[] argTypes = fastMethodSetter.getParameterTypes();
+ Class argType = argTypes != null ? argTypes[0] : null;
+ String msg = buildSetterErrorMsg(argType, target, value, "Can't set value on given object.");
+ getLog().error(msg);
+ throw new MetadataException("Error invoking method:" + fastMethodSetter.getName() + " in object:" + target.getClass().getName(), e);
+ }
+ }
+
+ private void init()
+ {
+ methodGraphGetter = buildMethodGraphGetter();
+ methodGraphSetter = buildMethodGraphSetter();
+ if(methodGraphGetter.length == 1)
+ {
+ singleMethodGraphGetter = methodGraphGetter[0];
+ singleMethodGraphSetter = methodGraphSetter[0];
+ nonNested = true;
+ }
+ initialized = true;
+ }
+
+ private FastMethod[] buildMethodGraphGetter()
+ {
+ List result = new ArrayList();
+ String[] fields = StringUtils.split(getName(), PATH_TOKEN);
+ PropertyDescriptor pd = null;
+ for(int i = 0; i < fields.length; i++)
+ {
+ String fieldName = fields[i];
+ Class clazz;
+ if(pd == null)
+ {
+ clazz = getDeclaringClass();
+ pd = findPropertyDescriptor(clazz, fieldName);
+ }
+ else
+ {
+ clazz = pd.getPropertyType();
+ pd = findPropertyDescriptor(clazz, fieldName);
+ }
+ Method method = pd.getReadMethod();
+ if(method == null)
+ {
+ throw new MetadataException("Can't get readMethod for property '"
+ + pd.getName() + "' in object '" + clazz.getName() + "'");
+ }
+ FastMethod m = FastClass.create(method.getDeclaringClass()).getMethod(method);
+ result.add(m);
+ }
+ return (FastMethod[]) result.toArray(new FastMethod[result.size()]);
+ }
+
+ private FastMethod[] buildMethodGraphSetter()
+ {
+ List result = new ArrayList();
+ String[] fields = StringUtils.split(getName(), PATH_TOKEN);
+ PropertyDescriptor pd = null;
+ for(int i = 0; i < fields.length; i++)
+ {
+ String fieldName = fields[i];
+ Class clazz;
+ if(pd == null)
+ {
+ clazz = getDeclaringClass();
+ pd = findPropertyDescriptor(clazz, fieldName);
+ }
+ else
+ {
+ clazz = pd.getPropertyType();
+ pd = findPropertyDescriptor(clazz, fieldName);
+ }
+ Method method = pd.getWriteMethod();
+ if(method == null)
+ {
+ throw new MetadataException("Can't get writeMethod for property '"
+ + pd.getName() + "' in object '" + clazz.getName() + "'");
+ }
+ FastMethod m = FastClass.create(method.getDeclaringClass()).getMethod(method);
+ result.add(m);
+ }
+ return (FastMethod[]) result.toArray(new FastMethod[result.size()]);
+ }
+
+ /** This implementation returns always 'false'. */
+ public boolean makeAccessible()
+ {
+ return false;
+ }
+}
Added: db/ojb/trunk/src/java/org/apache/ojb/broker/util/GUIDFactory.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/util/GUIDFactory.java?rev=422225&view=auto
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/util/GUIDFactory.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/util/GUIDFactory.java Sat Jul 15 07:09:47 2006
@@ -0,0 +1,118 @@
+package org.apache.ojb.broker.util;
+
+/* Copyright 2002-2005 The Apache Software Foundation
+ *
+ * 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.
+ */
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * A simple (and fast) factory for (human readable) GUID (Globally Unique ID) strings.
+ * <br/>
+ * A GUID is composed of three parts (separator is ':'):
+ * 1. A two part unique UID for this host
+ * 2. The IP-Address of the local machine
+ * <br/>
+ * An example GUID would be: -32766:1135679889968:84.157.57.223.
+ *
+ * @version $Id: GUIDFactory.java 365264 2005-12-31 19:42:46 +0100 (Sa, 31 Dez 2005) arminw $
+ */
+public class GUIDFactory
+{
+ private static final char SEPERATOR = ':';
+ private static final Object lock = new Object();
+
+ private static long WAIT_PERIOD = 100;
+ private static long lastTime = System.currentTimeMillis();
+ private static short lastCount = Short.MIN_VALUE;
+ /** the end piece of the GUID */
+ private static String endPiece;
+
+ /** holds the hostname of the local machine. */
+ private static String localIPAddress;
+
+ /**
+ * compute the local IP-Address
+ */
+ static
+ {
+ try
+ {
+ localIPAddress = InetAddress.getLocalHost().getHostAddress();
+ }
+ catch(UnknownHostException e)
+ {
+ System.err.println("[" + GUIDFactory.class.getName() + "]"
+ + " Can't lookup current IPAddress - GUID isn't globally unique, only for host. "
+ + e.getMessage());
+ localIPAddress = "localhost";
+ }
+ endPiece = new StringBuffer()
+ .append(Long.toString(lastTime))
+ .append(SEPERATOR)
+ .append(localIPAddress)
+ .toString();
+ }
+
+ public GUIDFactory()
+ {
+ }
+
+ /** Returns the next GUID string. */
+ public String next()
+ {
+ short count;
+
+ synchronized(lock)
+ {
+ if(lastCount == Short.MAX_VALUE)
+ {
+ boolean done = false;
+ /*
+ Use a similar algorithm as in java.rmi.server.UID
+ */
+ while(!done)
+ {
+ long current = System.currentTimeMillis();
+ if(current < lastTime + WAIT_PERIOD)
+ {
+ try
+ {
+ Thread.currentThread().sleep(WAIT_PERIOD);
+ }
+ catch(InterruptedException ignore)
+ {
+ // ignore exception
+ }
+ }
+ else
+ {
+ lastTime = current;
+ lastCount = Short.MIN_VALUE;
+ endPiece = new StringBuffer()
+ .append(SEPERATOR)
+ .append(lastTime)
+ .append(SEPERATOR)
+ .append(localIPAddress)
+ .toString();
+ done = true;
+ }
+ }
+ }
+ count = lastCount++;
+ }
+ return count + endPiece;
+ }
+}
Added: db/ojb/trunk/src/java/org/apache/ojb/broker/util/ReaderInputStream.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/util/ReaderInputStream.java?rev=422225&view=auto
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/util/ReaderInputStream.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/util/ReaderInputStream.java Sat Jul 15 07:09:47 2006
@@ -0,0 +1,234 @@
+package org.apache.ojb.broker.util;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+/**
+ * This class is a copy of {@link org.apache.tools.ant.util.ReaderInputStream}.
+ *
+ * @version $Id: $
+ */
+public class ReaderInputStream extends InputStream
+{
+
+ /** Source Reader */
+ private Reader in;
+
+ private String encoding = System.getProperty("file.encoding");
+
+ private byte[] slack;
+
+ private int begin;
+
+ /**
+ * Construct a <CODE>ReaderInputStream</CODE>
+ * for the specified <CODE>Reader</CODE>.
+ *
+ * @param reader <CODE>Reader</CODE>. Must not be <code>null</code>.
+ */
+ public ReaderInputStream(Reader reader)
+ {
+ in = reader;
+ }
+
+ /**
+ * Construct a <CODE>ReaderInputStream</CODE>
+ * for the specified <CODE>Reader</CODE>,
+ * with the specified encoding.
+ *
+ * @param reader non-null <CODE>Reader</CODE>.
+ * @param encoding non-null <CODE>String</CODE> encoding.
+ */
+ public ReaderInputStream(Reader reader, String encoding)
+ {
+ this(reader);
+ if(encoding == null)
+ {
+ throw new IllegalArgumentException("encoding must not be null");
+ }
+ else
+ {
+ this.encoding = encoding;
+ }
+ }
+
+ /**
+ * Reads from the <CODE>Reader</CODE>, returning the same value.
+ *
+ * @return the value of the next character in the <CODE>Reader</CODE>.
+ * @throws IOException if the original <code>Reader</code> fails to be read
+ */
+ public synchronized int read() throws IOException
+ {
+ if(in == null)
+ {
+ throw new IOException("Stream Closed");
+ }
+
+ byte result;
+ if(slack != null && begin < slack.length)
+ {
+ result = slack[begin];
+ if(++begin == slack.length)
+ {
+ slack = null;
+ }
+ }
+ else
+ {
+ byte[] buf = new byte[1];
+ if(read(buf, 0, 1) <= 0)
+ {
+ result = -1;
+ }
+ result = buf[0];
+ }
+
+ if(result < -1)
+ {
+ result += 256;
+ }
+
+ return result;
+ }
+
+ /**
+ * Reads from the <code>Reader</code> into a byte array
+ *
+ * @param b the byte array to read into
+ * @param off the offset in the byte array
+ * @param len the length in the byte array to fill
+ * @return the actual number read into the byte array, -1 at
+ * the end of the stream
+ * @throws IOException if an error occurs
+ */
+ public synchronized int read(byte[] b, int off, int len)
+ throws IOException
+ {
+ if(in == null)
+ {
+ throw new IOException("Stream Closed");
+ }
+
+ while(slack == null)
+ {
+ char[] buf = new char[len]; // might read too much
+ int n = in.read(buf);
+ if(n == -1)
+ {
+ return -1;
+ }
+ if(n > 0)
+ {
+ slack = new String(buf, 0, n).getBytes(encoding);
+ begin = 0;
+ }
+ }
+
+ if(len > slack.length - begin)
+ {
+ len = slack.length - begin;
+ }
+
+ System.arraycopy(slack, begin, b, off, len);
+
+ if((begin += len) >= slack.length)
+ {
+ slack = null;
+ }
+
+ return len;
+ }
+
+ /**
+ * Marks the read limit of the StringReader.
+ *
+ * @param limit the maximum limit of bytes that can be read before the
+ * mark position becomes invalid
+ */
+ public synchronized void mark(final int limit)
+ {
+ try
+ {
+ in.mark(limit);
+ }
+ catch(IOException ioe)
+ {
+ throw new RuntimeException(ioe.getMessage());
+ }
+ }
+
+
+ /**
+ * @return the current number of bytes ready for reading
+ * @throws IOException if an error occurs
+ */
+ public synchronized int available() throws IOException
+ {
+ if(in == null)
+ {
+ throw new IOException("Stream Closed");
+ }
+ if(slack != null)
+ {
+ return slack.length - begin;
+ }
+ if(in.ready())
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /** @return false - mark is not supported */
+ public boolean markSupported()
+ {
+ return false; // would be imprecise
+ }
+
+ /**
+ * Resets the StringReader.
+ *
+ * @throws IOException if the StringReader fails to be reset
+ */
+ public synchronized void reset() throws IOException
+ {
+ if(in == null)
+ {
+ throw new IOException("Stream Closed");
+ }
+ slack = null;
+ in.reset();
+ }
+
+ /**
+ * Closes the Stringreader.
+ *
+ * @throws IOException if the original StringReader fails to be closed
+ */
+ public synchronized void close() throws IOException
+ {
+ in.close();
+ slack = null;
+ in = null;
+ }
+}
Added: db/ojb/trunk/src/java/org/apache/ojb/broker/util/UnwrapHelper.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/util/UnwrapHelper.java?rev=422225&view=auto
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/util/UnwrapHelper.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/util/UnwrapHelper.java Sat Jul 15 07:09:47 2006
@@ -0,0 +1,468 @@
+package org.apache.ojb.broker.util;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * 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.
+ */
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.Statement;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.apache.ojb.broker.util.logging.Logger;
+import org.apache.ojb.broker.util.logging.LoggerFactory;
+
+/**
+ * This a helper class make available methods to unwrap {@link java.sql.Connection} and
+ * {@link java.sql.Statement} instances of connection-pool libraries,
+ * application server and other.
+ * <p/>
+ * This class supports predefined unwrap patterns for:
+ * <ul>
+ * <li>commons-DBCP</li>
+ * <li>JBoss</li>
+ * <li>enhydra.XAPool</li>
+ * <li>BEA Weblogic</li>
+ * <li>p6spy</li>
+ * </ul>
+ * To add new unwrap patterns use method {@link #addUnwrapPattern(Object[])}.
+ *
+ * @version $Id: $
+ */
+public class UnwrapHelper
+{
+ private Logger log = LoggerFactory.getLogger(UnwrapHelper.class);
+
+ private static final int UNWARP_CONNECTION = 1;
+ private static final int UNWARP_STATEMENT = 2;
+ private static final Object[] EMPTY_ARG = new Object[]{};
+ public static final Class[] EMPTY_TYPE = new Class[]{};
+ public static final Integer TYPE_METHOD = new Integer(5);
+ public static final Integer TYPE_FIELD = new Integer(6);
+ /**
+ * Represents the information of how to unwrap wrapped {@link java.sql.Connection}
+ * and {@link java.sql.PreparedStatement} instances of popular connection-pool libraries,
+ * application server and other libraries.
+ * <p/>
+ * The array have to be a [n][7] length object array. The following arguments will be expected:
+ * <ul>
+ * <li>predefinedPatterns[i][0] = the vendor, product name as {@link String}</li>
+ *
+ * <li>predefinedPatterns[i][1] = use {@link #TYPE_METHOD} if access to the wrapped connection via method call
+ * is possible, use {@link #TYPE_FIELD} if access to a field can be used</li>
+ * <li>predefinedPatterns[i][2] = use {@link #EMPTY_TYPE} if a no-arg method call is needed, otherwise
+ * specify the argument type class array - in this case always a single argument
+ * type is expected and the source object (object to unwarp) was used as argument object when
+ * calling {@link #unwrapConnection(Class, java.sql.Connection)} or
+ * {@link #unwrapStatement(Class, java.sql.Statement)}</li>
+ * <li>predefinedPatterns[i][3] = the name of the method/field to lookup the wrapped connection
+ * as {@link String}<br/><br/></li>
+ *
+ * <li>predefinedPatterns[i][4] = use {@link #TYPE_METHOD} if access to the wrapped statment via method call
+ * is possible, use {@link #TYPE_FIELD} if access to a field can be used</li></li>
+ * <li>predefinedPatterns[i][5] = use {@link #EMPTY_TYPE} if a no-arg method call is needed, otherwise
+ * specify the argument type class array - in this case always a single argument
+ * type is expected and the source object (object to unwarp) was used as argument object when
+ * calling {@link #unwrapConnection(Class, java.sql.Connection)} or
+ * {@link #unwrapStatement(Class, java.sql.Statement)}</li>
+ * <li>predefinedPatterns[i][6] = the name of the method/field to unwrap the statement<br/><br/></li>
+ * </ul>
+ * Example:
+ * <code>
+ * protected static Object[][] predefinedPatterns = {
+ * {"common-DBCP", TYPE_METHOD, PARAM_TYPE_EMPTY, "getInnermostDelegate", TYPE_METHOD, PARAM_TYPE_EMPTY, "getInnermostDelegate"},
+ * {"enhydra.XAPool", TYPE_FIELD, null, "con", TYPE_FIELD, null, "ps"},
+ * ....
+ * </code>
+ */
+ private static final Object[][] predefinedPatterns = {
+ {"common-DBCP", TYPE_METHOD, EMPTY_TYPE, "getInnermostDelegate", TYPE_METHOD, EMPTY_TYPE, "getInnermostDelegate"},
+ {"JBoss", TYPE_METHOD, EMPTY_TYPE, "getUnderlyingConnection", TYPE_METHOD, EMPTY_TYPE, "getUnderlyingStatement"},
+ {"enhydra.XAPool", TYPE_FIELD, null, "con", TYPE_FIELD, null, "ps"},
+ {"BEA Weblogic", TYPE_METHOD, EMPTY_TYPE, "getVendorConnection", null, null, null},
+ {"p6spy", TYPE_METHOD, EMPTY_TYPE, "getJDBC", TYPE_METHOD, EMPTY_TYPE, "getJDBC"}
+ };
+
+ /**
+ * The active unwrap patterns.
+ */
+ private Object[][] unwrapPatterns = new Object[][]{};
+ private Object[][] matchedPatterns;
+ private boolean optimized;
+
+
+ /**
+ * Default constructor, use predefined unwrap patterns and optimized
+ * search, see {@link #UnwrapHelper(boolean, boolean)}.
+ */
+ public UnwrapHelper()
+ {
+ this(true, true);
+ }
+
+ /**
+ * Alternative constructor.
+ * @param usePredefined If <em>true</em> the predefined unwrap patterns will be used,
+ * else no patterns are provided (add pattern with {@link #addUnwrapPattern(Object[])}).
+ * @param optimized If <em>true</em> all matching patterns will be bundled and used to unwrap,
+ * if <em>false</em> always all patterns are used to search for a unwrap match.
+ */
+ public UnwrapHelper(boolean usePredefined, boolean optimized)
+ {
+ resetMatchedPatterns();
+ this.optimized = optimized;
+ if(usePredefined)
+ {
+ if(log.isDebugEnabled()) log.debug("Activate predefined unwrap patterns");
+ for(int i = 0; i < predefinedPatterns.length; i++)
+ {
+ Object[] pattern = predefinedPatterns[i];
+ addUnwrapPattern(pattern);
+ }
+ }
+ }
+
+ /** Return the current unwrap patterns. */
+ public Object[][] getUnwrapPatterns()
+ {
+ return unwrapPatterns;
+ }
+
+ /**
+ * Add a new unwrap pattern. The object array of length 7 have to be
+ * the following arguments (a vendor string, 3 arguments to unwrap connections,
+ * 3 arguments to unwrap statements):<br/><br/>
+ * <ul>
+ * <li>
+ * pattern[0] = the vendor, product name as {@link String}.<br/><br/>
+ * </li>
+ *
+ * <li>
+ * pattern[1] = use {@link #TYPE_METHOD} if access to the wrapped connection is done via
+ * method call or use {@link #TYPE_FIELD} to specify access via field.
+ * </li>
+ * <li>
+ * pattern[2] = specify the method argument for connection unwrap. Only two types are
+ * supported: non-argument methods and single argument type methods. If field access
+ * is used nullify this argument.
+ * <br/>
+ * Non argument methods can use {@link #EMPTY_TYPE} or simply <em>null</em>.
+ * <br/>
+ * The single argument type (specified as class, class array or full qualified
+ * class name string) use the source object (object to unwarp) as argument
+ * object when calling
+ * {@link #unwrapConnection(Class, java.sql.Connection)}.
+ * </li>
+ * <li>
+ * pattern[3] = the name of the method/field to unwrap the connection.<br/><br/>
+ * </li>
+ *
+ * <li>
+ * pattern[4] = use {@link #TYPE_METHOD} if access to the wrapped statment via method call
+ * is possible, use {@link #TYPE_FIELD} if access to a field can be used
+ * </li>
+ * <li>
+ * pattern[5] = specify the method argument for statement unwrap. Only two types are
+ * supported: non-argument methods and single argument type methods. If field access
+ * is used nullify this argument.
+ * <br/>
+ * Non argument methods can use {@link #EMPTY_TYPE} or simply <em>null</em>.
+ * <br/>
+ * The single argument type (specified as class, class array or full qualified
+ * class name string) use the source object (object to unwarp) as argument
+ * object when calling {@link #unwrapStatement(Class, java.sql.Statement)}.
+ * </li>
+ * <li>
+ * pattern[6] = the name of the method/field to unwrap the statement.<br/><br/>
+ * </li>
+ * </ul>
+ * Here is an example how to use this method:
+ * <code>
+ * Object pattern = new Object[]{"JBoss", TYPE_METHOD, EMPTY_TYPE, "getUnderlyingConnection",
+ * TYPE_METHOD, EMPTY_TYPE, "getUnderlyingStatement"};
+ * unwarpHelper.addUnwrapPattern(pattern);
+ * </code>
+ *
+ * @param pattern The unwrap pattern array.
+ */
+ public void addUnwrapPattern(final Object[] pattern)
+ {
+ // check connection method argument
+ Object argType = pattern[2];
+ if(argType == null)
+ {
+ pattern[2] = EMPTY_TYPE;
+ }
+ else if(argType instanceof String)
+ {
+ String arg = (String) argType;
+ try
+ {
+ Class tmp = ClassHelper.getClass(arg);
+ pattern[2] = new Class[]{tmp};
+ }
+ catch(ClassNotFoundException e)
+ {
+ log.error("Can't lookup method argument type "
+ + arg + " of pattern " + ArrayUtils.toString(pattern), e);
+ }
+ }
+ else if(argType instanceof Class)
+ {
+ pattern[2] = new Class[]{(Class)argType};
+ }
+ // check statement method argument
+ argType = pattern[5];
+ if(argType == null)
+ {
+ pattern[5] = EMPTY_TYPE;
+ }
+ else if(argType instanceof String)
+ {
+ String arg = (String) argType;
+ try
+ {
+ Class tmp = ClassHelper.getClass(arg);
+ pattern[5] = new Class[]{tmp};
+ }
+ catch(ClassNotFoundException e)
+ {
+ log.error("Can't lookup method argument type "
+ + arg + " of pattern " + ArrayUtils.toString(pattern), e);
+ }
+ }
+ else if(argType instanceof Class)
+ {
+ pattern[5] = new Class[]{(Class)argType};
+ }
+
+ Object[][] tmp = new Object[][]{pattern};
+ unwrapPatterns = (Object[][]) ArrayUtils.addAll(unwrapPatterns, tmp);
+ // force synchronization of optimized patterns
+ if(optimized) resetMatchedPatterns();
+ }
+
+ protected Object genericUnwrap(final Class classToMatch, final Object toUnwrap, final int type)
+ {
+ Object result;
+ if(optimized)
+ {
+ if(matchedPatterns.length == 0)
+ {
+ ArrayList matches = new ArrayList();
+ result = loopUnwrap(unwrapPatterns, classToMatch, toUnwrap, type, matches);
+ matchedPatterns = (Object[][]) matches.toArray(new Object[matches.size()][]);
+ }
+ else
+ {
+ result = loopUnwrap(matchedPatterns, classToMatch, toUnwrap, type, null);
+ }
+ }
+ else
+ {
+ result = loopUnwrap(unwrapPatterns, classToMatch, toUnwrap, type, null);
+ }
+ return result;
+ }
+
+ protected Object loopUnwrap(Object[][] patterns, final Class classToMatch, final Object toUnwrap, final int type, final List matchedPatterns)
+ {
+ if(classToMatch == null)
+ {
+ return null;
+ }
+ if(classToMatch.isAssignableFrom(toUnwrap.getClass()))
+ {
+ return toUnwrap;
+ }
+ Object unwrapped = null;
+
+ int i = 0;
+ try
+ {
+ for(; i < patterns.length; i++)
+ {
+ Object[] pattern = patterns[i];
+ unwrapped = unwrap(pattern, toUnwrap, type);
+ if(unwrapped != null)
+ {
+ if(matchedPatterns != null)
+ {
+ matchedPatterns.add(pattern);
+ }
+ break;
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ //e.printStackTrace();
+ // ignore
+ if(log.isDebugEnabled())
+ {
+ if(type == UNWARP_CONNECTION)
+ {
+ log.debug("Unwrap of connection failed using unwrap rule for " + unwrapPatterns[i][0] + " connections", e);
+ }
+ else
+ {
+ log.debug("Unwrap of prepared stmt failed using unwrap rule for " + unwrapPatterns[i][0] + " statements", e);
+ }
+ }
+ }
+
+ if(unwrapped != null)
+ {
+ if(classToMatch.isAssignableFrom(unwrapped.getClass()))
+ {
+ // Bingo!
+ }
+ else
+ {
+ // When using e.g. both DBCP and P6Spy we have to recursively unwrap
+ unwrapped = loopUnwrap(patterns, classToMatch, unwrapped, type, matchedPatterns);
+ }
+ }
+ return unwrapped;
+ }
+
+ private Object unwrap(final Object[] pattern, final Object toUnwrap, final int type) throws Exception
+ {
+ Object unwrapped = null;
+ if(type == UNWARP_CONNECTION && pattern[3] != null)
+ {
+ unwrapped = reflectObject(toUnwrap, pattern[1].equals(TYPE_METHOD), (Class[]) pattern[2], (String) pattern[3]);
+ }
+ else if(type == UNWARP_STATEMENT && pattern[6] != null)
+ {
+ unwrapped = reflectObject(toUnwrap, pattern[4].equals(TYPE_METHOD), (Class[]) pattern[5], (String) pattern[6]);
+ }
+ else
+ {
+ if(log.isDebugEnabled())
+ {
+ log.debug("Can't use the specified pattern to unwarp "
+ + (type == UNWARP_CONNECTION ? "connection" : "statement")
+ + ": " + ArrayUtils.toString(pattern));
+ }
+ }
+ return unwrapped;
+ }
+
+ private Object reflectObject(final Object source, final boolean methodType, final Class[] paramType, final String fieldOrMethodName) throws Exception
+ {
+ Object unwrapped = null;
+ if(methodType)
+ {
+ final Method method;
+ method = ClassHelper.getMethod(source, fieldOrMethodName, paramType);
+ if(method != null)
+ {
+ if(!method.isAccessible())
+ {
+ method.setAccessible(true);
+ }
+ Object[] arg = (paramType == null || paramType.length == 0) ? EMPTY_ARG : new Object[]{source};
+ unwrapped = method.invoke(source, arg);
+ }
+ }
+ else
+ {
+ final Field field;
+ field = ClassHelper.getField(source.getClass(), fieldOrMethodName);
+ if(field != null)
+ {
+ if(!field.isAccessible())
+ {
+ field.setAccessible(true);
+ }
+ unwrapped = field.get(source);
+ }
+ }
+ return unwrapped;
+ }
+
+ /**
+ * Rekursive unwrap specified {@link java.sql.Connection} till target
+ * class is matched.
+ *
+ * @param target The target class (subclass of {@link java.sql.Connection} is mandatory).
+ * @param source The wrapped connection instance.
+ * @return The unwrapped connection or <em>null</em> if no match is possible.
+ */
+ public Connection unwrapConnection(final Class target, final Connection source)
+ {
+ Connection result = (Connection) genericUnwrap(target, source, UNWARP_CONNECTION);
+ if(result == null && log.isDebugEnabled())
+ {
+ log.debug("Could not unwrap source " + source.getClass().getName()
+ + " to target class " + target.getName());
+ }
+ return result;
+ }
+
+ /**
+ * Rekursive unwrap specified {@link java.sql.Statement} till target
+ * class is matched.
+ *
+ * @param target The target class (subclass of {@link java.sql.PreparedStatement} is mandatory).
+ * @param source The wrapped statement instance.
+ * @return The unwrapped statement or <em>null</em> if no match is possible.
+ */
+ public Statement unwrapStatement(final Class target, final Statement source)
+ {
+ Statement result = (Statement) genericUnwrap(target, source, UNWARP_STATEMENT);
+ if(result == null && log.isDebugEnabled())
+ {
+ log.debug("Could not unwrap source " + source.getClass().getName()
+ + " to target class " + target.getName());
+ }
+ return result;
+ }
+
+ /**
+ * Rekursive unwrap specified {@link java.sql.Statement} till target
+ * class is matched.
+ *
+ * @param target The target class (subclass of {@link java.sql.PreparedStatement} is mandatory).
+ * @param source The wrapped statement instance.
+ * @return The unwrapped statement or <em>null</em> if no match is possible.
+ */
+ public PreparedStatement unwrapStatement(final Class target, final PreparedStatement source)
+ {
+ return (PreparedStatement) unwrapStatement(target, (Statement) source);
+ }
+
+ private void resetMatchedPatterns()
+ {
+ matchedPatterns = new Object[][]{};
+ }
+
+ public String toString()
+ {
+ ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
+ buf.append("Supported unwrap pattern: ");
+ for(int i = 0; i < unwrapPatterns.length; i++)
+ {
+ buf.append(ArrayUtils.toString(unwrapPatterns[i]));
+ }
+ return buf.toString();
+ }
+}
Added: db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerTransientImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerTransientImpl.java?rev=422225&view=auto
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerTransientImpl.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerTransientImpl.java Sat Jul 15 07:09:47 2006
@@ -0,0 +1,51 @@
+package org.apache.ojb.broker.util.sequence;
+
+/* Copyright 2002-2005 The Apache Software Foundation
+ *
+ * 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.
+ */
+
+import org.apache.ojb.broker.PersistenceBroker;
+import org.apache.ojb.broker.PersistenceBrokerInternal;
+import org.apache.ojb.broker.metadata.FieldDescriptor;
+
+/**
+ * For internal use only!
+ * This class is used to create transient primary key values for transient
+ * {@link org.apache.ojb.broker.Identity} objects.
+ *
+ * @version $Id: SequenceManagerTransientImpl.java 365232 2005-12-21 23:36:07 +0100 (Mi, 21 Dez 2005) tomdz $
+ */
+public class SequenceManagerTransientImpl extends AbstractSequenceManager
+{
+ /*
+ Use keyword 'volatile' to make decrement of a long value an
+ atomic operation
+ */
+ private static volatile long tempKey = -1000;
+
+ public SequenceManagerTransientImpl(PersistenceBrokerInternal broker)
+ {
+ super(broker);
+ }
+
+ protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException
+ {
+ /*
+ arminw:
+ We need unique 'dummy keys' for new objects before storing.
+ Variable 'tempKey' is declared volatile, thus decrement should be atomic
+ */
+ return --tempKey;
+ }
+}
Added: db/ojb/trunk/src/java/org/apache/ojb/odmg/Image.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/odmg/Image.java?rev=422225&view=auto
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/odmg/Image.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/odmg/Image.java Sat Jul 15 07:09:47 2006
@@ -0,0 +1,522 @@
+package org.apache.ojb.odmg;
+
+/* Copyright 2002-2005 The Apache Software Foundation
+ *
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.ClassUtils;
+import org.apache.ojb.broker.Identity;
+import org.apache.ojb.broker.IdentityFactory;
+import org.apache.ojb.broker.OJBRuntimeException;
+import org.apache.ojb.broker.PersistenceBrokerInternal;
+import org.apache.ojb.broker.core.proxy.CollectionProxy;
+import org.apache.ojb.broker.core.proxy.CollectionProxyListener;
+import org.apache.ojb.broker.metadata.CollectionDescriptor;
+import org.apache.ojb.broker.metadata.FieldType;
+import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
+import org.apache.ojb.broker.util.BrokerHelper;
+import org.apache.ojb.broker.util.logging.Logger;
+import org.apache.ojb.broker.util.logging.LoggerFactory;
+
+/**
+ * This class encapsulates classes used to take persistence capable object
+ * state snapshoot and to detect changed fields or references.
+ *
+ * @version $Id: Image.java 365232 2005-12-21 23:36:07 +0100 (Mi, 21 Dez 2005) tomdz $
+ */
+public abstract class Image
+{
+ static Logger log = LoggerFactory.getLogger(Image.class);
+ private long timestamp = System.currentTimeMillis();
+
+ private Image()
+ {
+ }
+
+ boolean illegalImageComparison(Image oldImage)
+ {
+ return timestamp < oldImage.timestamp;
+ }
+
+ public abstract void cleanup(boolean reuse);
+
+ public abstract boolean modified(Image other);
+
+ abstract void referenceProcessing(Image oldImage);
+
+ public void performReferenceDetection(Image oldImage)
+ {
+ if(illegalImageComparison(oldImage))
+ {
+ throw new ImageException("The specified Image object is newer than current one, wrong Image order!");
+ }
+ referenceProcessing(oldImage);
+ }
+
+ //===================================================================
+ // inner class
+ //===================================================================
+ public static class MultipleRef extends Image implements CollectionProxyListener
+ {
+ static final int IS_NORMAL_OBJECT = 11;
+ static final int IS_MATERIALIZED_PROXY = 13;
+ static final int IS_UNMATERIALIZED_PROXY = 17;
+
+ private ImageListener listener;
+ private final CollectionDescriptor cod;
+ private final Object collectionOrArray;
+ private Map references;
+ private int status;
+ private boolean hasTransientIdentity;
+ private boolean isRefreshed;
+
+ public MultipleRef(ImageListener listener, CollectionDescriptor cod, Object collectionOrArray)
+ {
+ this.listener = listener;
+ this.cod = cod;
+ this.collectionOrArray = collectionOrArray;
+ this.isRefreshed = true;
+ this.hasTransientIdentity = false;
+ this.references = Collections.EMPTY_MAP;
+ init();
+ }
+
+ private void init()
+ {
+ CollectionProxy colProxy = listener.getBroker().getProxyFactory().getCollectionProxy(collectionOrArray);
+ if(colProxy != null)
+ {
+ if(colProxy.isLoaded())
+ {
+ status = IS_MATERIALIZED_PROXY;
+ /*
+ TODO: avoid this cast
+ e.g. change CollectionProxy interface - CollectionProxy should
+ extend Collection to support Iterator
+ */
+ handleReferencedObjects(colProxy.iterator());
+ }
+ else
+ {
+ status = IS_UNMATERIALIZED_PROXY;
+ if(log.isDebugEnabled()) log.debug("Unmaterialized proxy collection, use proxy listener");
+ colProxy.addListener(this);
+ }
+ }
+ else
+ {
+ status = IS_NORMAL_OBJECT;
+ if(collectionOrArray != null)
+ {
+ Iterator it = BrokerHelper.getCollectionIterator(listener.getBroker(), collectionOrArray);
+ handleReferencedObjects(it);
+ }
+ }
+ }
+
+ void handleReferencedObjects(Iterator it)
+ {
+ if(it == null) return;
+ references = new HashMap();
+ if(log.isDebugEnabled()) log.debug("Handle collection references");
+ IdentityFactory idFac = listener.getBroker().serviceIdentity();
+ Identity oid;
+ Object obj;
+ while(it.hasNext())
+ {
+ obj = it.next();
+ oid = idFac.buildIdentity(obj);
+ if(!hasTransientIdentity && oid.isTransient())
+ {
+ hasTransientIdentity = true;
+ }
+ references.put(oid, obj);
+ }
+ }
+
+ public void cleanup(boolean reuse)
+ {
+ if(log.isDebugEnabled()) log.debug("Cleanup collection image, reuse=" + reuse);
+ if(reuse)
+ {
+ isRefreshed = false;
+ }
+ else
+ {
+ if(status == IS_UNMATERIALIZED_PROXY)
+ {
+ CollectionProxy colProxy = listener.getBroker().getProxyFactory().getCollectionProxy(collectionOrArray);
+ if(colProxy != null)
+ {
+ colProxy.removeListener(this);
+ }
+ }
+ }
+ }
+
+ void referenceProcessing(Image oldImage)
+ {
+ MultipleRef oldRefs = (MultipleRef) oldImage;
+ if(incommensurableProxies(oldRefs))
+ {
+ PersistenceBrokerInternal pb = listener.getBroker();
+ if(isUnmaterializedProxy()) handleReferencedObjects(BrokerHelper.getCollectionIterator(pb, collectionOrArray));
+ if(oldRefs.isUnmaterializedProxy()) oldRefs.handleReferencedObjects(BrokerHelper.getCollectionIterator(pb, oldRefs.collectionOrArray));
+ }
+ if(!isRefreshed) refreshIdentities();
+ if(!oldRefs.isRefreshed) oldRefs.refreshIdentities();
+
+ // find deleted reference objects
+ if(oldRefs.references.size() > 0)
+ {
+ Iterator oldIter = oldRefs.references.entrySet().iterator();
+ while(oldIter.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) oldIter.next();
+ Identity oldOid = (Identity) entry.getKey();
+ /*
+ search for deleted objects: if in the new image an object
+ from the old image is not contained, we found a deleted object
+ */
+ if(!isUnmaterializedProxy() && !containsReference(oldOid))
+ {
+ listener.deletedXToN(cod, entry.getValue(), oldOid);
+ }
+ }
+ }
+
+ // find new reference objects
+ if(references.size() > 0)
+ {
+ Iterator newIter = references.entrySet().iterator();
+ while(newIter.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) newIter.next();
+ Identity newOid = (Identity) entry.getKey();
+ /*
+ search for added objects: if in the old image an object
+ from the new image is not contained, we found a added object
+ */
+ if(!oldRefs.containsReference(newOid))
+ {
+ listener.addedXToN(cod, entry.getValue(), newOid);
+ }
+ }
+ }
+ }
+
+ /**
+ * To detect deleted (added) collection objects it's necessary iterate over the old (new) image collection.
+ * If the old (new) image collection is a unmaterialized proxy we have to check if the new (old) image collection
+ * is the same proxy instance or not.
+ * E.g. if the user exchange one another the unmaterialized proxy collection objects of two main objects,
+ * then both proxy need to be materialized to assign the changed FK field values.
+ */
+ private boolean incommensurableProxies(MultipleRef oldImage)
+ {
+ boolean result = false;
+ // deleted objects
+ if(oldImage.isUnmaterializedProxy() || isUnmaterializedProxy())
+ {
+ result = collectionOrArray != oldImage.collectionOrArray;
+ }
+ return result;
+ }
+
+ private void refreshIdentities()
+ {
+ // if no transient identities are used, nothing to do
+ if(hasTransientIdentity && references.size() > 0)
+ {
+ hasTransientIdentity = false;
+ // we need independent key list from Map
+ List list = new ArrayList(references.keySet());
+ IdentityFactory idFac = listener.getBroker().serviceIdentity();
+ Identity oid, newOid;
+ Object obj;
+ for(int i = 0; i < list.size(); i++)
+ {
+ oid = (Identity) list.get(i);
+ if(oid.isTransient())
+ {
+ obj = references.remove(oid);
+ newOid = idFac.buildIdentity(obj);
+ references.put(newOid, obj);
+ if(!hasTransientIdentity && oid.isTransient())
+ {
+ hasTransientIdentity = true;
+ }
+ }
+ }
+ isRefreshed = true;
+ }
+ }
+
+ /**
+ * Always return 'false', because changed 1:n or m:n references do not
+ * affect the main object.
+ */
+ public boolean modified(Image other)
+ {
+ return false;
+ }
+
+ boolean containsReference(Identity oid)
+ {
+ if(!isRefreshed) refreshIdentities();
+ return references.containsKey(oid);
+ }
+
+ Map getIdentityReferenceObjectMap()
+ {
+ if(!isRefreshed) refreshIdentities();
+ return references;
+ }
+
+ boolean isMaterializedProxy()
+ {
+ return status == IS_MATERIALIZED_PROXY;
+ }
+
+ boolean isUnmaterializedProxy()
+ {
+ return status == IS_UNMATERIALIZED_PROXY;
+ }
+
+
+ // CollectionProxy Listener methods
+ //---------------------------------
+ public void beforeLoading(CollectionProxy colProxy)
+ {
+ //noop
+ }
+
+ public void afterLoading(CollectionProxy colProxy)
+ {
+ if(status == IS_UNMATERIALIZED_PROXY)
+ {
+ status = IS_MATERIALIZED_PROXY;
+ handleReferencedObjects(colProxy.iterator());
+ colProxy.removeListener(this);
+ }
+ }
+
+ public String toString()
+ {
+ return ClassUtils.getShortClassName(this.getClass()) + "[references-size="
+ + (references != null ? "" + references.size() : "undefined") + "]";
+ }
+ }
+
+ //===================================================================
+ // inner class
+ //===================================================================
+ public static class SingleRef extends Image
+ {
+ private Object referenceObjOrProxy;
+ private Identity oid = null;
+ private final ImageListener listener;
+ private final ObjectReferenceDescriptor ord;
+
+ public SingleRef(ImageListener listener, ObjectReferenceDescriptor ord, Object reference)
+ {
+ this.listener = listener;
+ this.ord = ord;
+ this.referenceObjOrProxy = reference;
+ }
+
+ public void cleanup(boolean reuse)
+ {
+ if(!reuse)
+ {
+ referenceObjOrProxy = null;
+ }
+ }
+
+ void referenceProcessing(Image oldImage)
+ {
+ SingleRef oldRef = (SingleRef) oldImage;
+ boolean isSame = getReferenceObjectOrProxy() == oldRef.getReferenceObjectOrProxy();
+ if(!isSame)
+ {
+ Identity newOid = getIdentity();
+ Identity oldOid = oldRef.getIdentity();
+ if(newOid == null)
+ {
+ if(oldOid != null)
+ {
+ listener.deletedOneToOne(ord, oldRef.getReferenceObjectOrProxy(), oldOid, true);
+ }
+ }
+ else
+ {
+ if(oldOid == null)
+ {
+ listener.addedOneToOne(ord, getReferenceObjectOrProxy(), newOid);
+ }
+ else
+ {
+ if(!newOid.equals(oldOid))
+ {
+ listener.deletedOneToOne(ord, oldRef.getReferenceObjectOrProxy(), oldOid, false);
+ listener.addedOneToOne(ord, getReferenceObjectOrProxy(), newOid);
+ }
+ }
+ }
+ }
+ }
+
+ public Object getReferenceObjectOrProxy()
+ {
+ return referenceObjOrProxy;
+ }
+
+ private Identity getIdentity()
+ {
+ if(oid == null || oid.isTransient())
+ {
+ if(referenceObjOrProxy != null)
+ {
+ oid = listener.getBroker().serviceIdentity().buildIdentity(referenceObjOrProxy);
+ }
+ }
+ return oid;
+ }
+
+ /**
+ * If a 1:1 reference has changed it will
+ * affects the main object (FK needs update).
+ */
+ public boolean modified(Image toCompare)
+ {
+ boolean modified = false;
+ if(!(this == toCompare))
+ {
+ if(toCompare instanceof Image.SingleRef)
+ {
+ Image.SingleRef other = (Image.SingleRef) toCompare;
+ Identity current = getIdentity();
+ Identity otherOid = other.getIdentity();
+ modified = current != null ? !current.equals(otherOid) : !(otherOid == null);
+ }
+ }
+ return modified;
+ }
+
+ public String toString()
+ {
+ return ClassUtils.getShortClassName(this.getClass()) + "[reference=" + getIdentity() + "]";
+ }
+ }
+
+ //===================================================================
+ // inner class
+ //===================================================================
+ public static class Field extends Image
+ {
+ private final FieldType type;
+ private final Object value;
+
+ public Field(FieldType type, Object value)
+ {
+ this.type = type;
+ this.value = value;
+ }
+
+ public void cleanup(boolean reuse)
+ {
+ }
+
+ void referenceProcessing(Image oldImage)
+ {
+ // nothing to do
+ }
+
+ /** If a field value has changed return 'true'. */
+ public boolean modified(Image other)
+ {
+ boolean result = false;
+ if(this == other)
+ {
+ result = true;
+ }
+ else
+ {
+ if(other instanceof Field)
+ {
+ result = !type.equals(value, ((Field) other).value);
+ }
+ }
+ return result;
+ }
+
+ public String toString()
+ {
+ return ClassUtils.getShortClassName(this.getClass()) + "[type=" + type + ", value=" + value + "]";
+ }
+ }
+
+ //===================================================================
+ // inner interface
+ //===================================================================
+ public static interface ImageListener
+ {
+ public void addedOneToOne(ObjectReferenceDescriptor ord, Object refObjOrProxy, Identity oid);
+
+ public void deletedOneToOne(ObjectReferenceDescriptor ord, Object refObjOrProxy, Identity oid, boolean needsUnlink);
+
+ public void addedXToN(CollectionDescriptor ord, Object refObjOrProxy, Identity oid);
+
+ public void deletedXToN(CollectionDescriptor ord, Object refObjOrProxy, Identity oid);
+
+ public PersistenceBrokerInternal getBroker();
+ }
+
+ //====================================================
+ // inner class
+ //====================================================
+
+ /**
+ * Thrown if something unexpected is happen when handling the
+ * object images for state detection.
+ */
+ public static class ImageException extends OJBRuntimeException
+ {
+ public ImageException()
+ {
+ }
+
+ public ImageException(String msg)
+ {
+ super(msg);
+ }
+
+ public ImageException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ public ImageException(String msg, Throwable cause)
+ {
+ super(msg, cause);
+ }
+ }
+}
Added: db/ojb/trunk/src/test/org/apache/ojb/Test_Repository_Renamed_DTD.xml
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/Test_Repository_Renamed_DTD.xml?rev=422225&view=auto
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/Test_Repository_Renamed_DTD.xml (added)
+++ db/ojb/trunk/src/test/org/apache/ojb/Test_Repository_Renamed_DTD.xml Sat Jul 15 07:09:47 2006
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+#/* Copyright 2003-2004 The Apache Software Foundation
+ *
+ * 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.
+ */
+-->
+<!--
+This is a test repository used in junit test org.apache.ojb.broker.metadata.MetadataTest
+Runtime reading of repository files.
+DO NOT CHANGE!
+-->
+<!DOCTYPE descriptor-repository SYSTEM "test_renamed_repository.dtd">
+
+
+<descriptor-repository version="1.1" isolation-level="read-uncommitted">
+
+ <!--
+ NOTE: This is a test descriptor used within
+ the junit test suite, DO NOT change any value.
+ -->
+
+ <!-- add some custom attributes -->
+ <attribute
+ attribute-name="attribute-repository-1"
+ attribute-value="attribute-repository-test-value-1">
+ </attribute>
+
+ <attribute
+ attribute-name="attribute-repository-2"
+ attribute-value="attribute-repository-test-value-2">
+ </attribute>
+
+ <jdbc-connection-descriptor
+ jcd-alias="runtime_2"
+ platform="Hsqldb"
+ jdbc-level="2.0"
+ driver="org.hsqldb.jdbcDriver"
+ protocol="jdbc"
+ subprotocol="hsqldb"
+ dbalias="../OJB_FarAway"
+ username="sa"
+ password=""
+ batch-mode="false"
+ >
+
+ <object-cache class="org.apache.ojb.broker.cache.ObjectCacheEmptyImpl">
+ <attribute attribute-name="attr_con" attribute-value="555"/>
+ </object-cache>
+
+ <connection-factory
+ class="org.apache.ojb.broker.accesslayer.ConnectionFactoryPooledImpl"
+ validationQuery="select count(*) from OJB_HL_SEQ"
+ >
+ <attribute attribute-name="maxActive" attribute-value="5"/>
+ <attribute attribute-name="whenExhaustedAction" attribute-value="0"/>
+ </connection-factory>
+
+ <sequence-manager className="org.apache.ojb.broker.util.sequence.SequenceManagerHighLowImpl">
+ <attribute attribute-name="grabSize" attribute-value="5"/>
+ </sequence-manager>
+
+ <!-- add some custom attributes -->
+ <attribute
+ attribute-name="attribute-connection-1"
+ attribute-value="attribute-connection-test-value-1">
+ </attribute>
+
+ <attribute
+ attribute-name="attribute-connection-2"
+ attribute-value="attribute-connection-test-value-2">
+ </attribute>
+
+ </jdbc-connection-descriptor>
+
+ <!-- test pc-class, this class is also declared in junit test metadata,
+ so be careful in handle this metadata -->
+ <class-descriptor
+ class="org.apache.ojb.broker.metadata.MetadataTest$CacheObject"
+ table="DO NOT USE"
+ >
+
+ <object-cache class="org.apache.ojb.broker.cache.ObjectCacheDefaultImpl">
+ <attribute attribute-name="attr_class" attribute-value="444"/>
+ </object-cache>
+
+ <field-descriptor
+ name="objId"
+ column="OBJ_ID"
+ jdbc-type="INTEGER"
+ primarykey="true"
+ autoincrement="true"
+ />
+
+ <field-descriptor
+ name="name"
+ column="NAME"
+ jdbc-type="VARCHAR"
+ />
+ </class-descriptor>
+
+</descriptor-repository>
Added: db/ojb/trunk/src/test/org/apache/ojb/broker/JdbcJavaObjectTest.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/broker/JdbcJavaObjectTest.java?rev=422225&view=auto
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/broker/JdbcJavaObjectTest.java (added)
+++ db/ojb/trunk/src/test/org/apache/ojb/broker/JdbcJavaObjectTest.java Sat Jul 15 07:09:47 2006
@@ -0,0 +1,227 @@
+package org.apache.ojb.broker;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * 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.
+ */
+
+import java.lang.Object;
+import java.io.Serializable;
+
+import org.apache.ojb.junit.PBTestCase;
+import org.apache.ojb.broker.query.QueryFactory;
+import org.apache.ojb.broker.query.Query;
+import org.apache.ojb.broker.query.Criteria;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.EqualsBuilder;
+
+/**
+ * This test class provide tests for JAVA_OBJECT handling.
+ *
+ * @version $Id: $
+ */
+public class JdbcJavaObjectTest extends PBTestCase
+{
+ public static void main(String[] args)
+ {
+ String[] arr = {JdbcJavaObjectTest.class.getName()};
+ junit.textui.TestRunner.main(arr);
+ }
+
+ public void testInsert()
+ {
+ Container c = new Container("testInsert", new Editor(2, "object_test"), new Editor(3, "editor_test"));
+ doInsert(c);
+ }
+
+ public void testDelete()
+ {
+ Container c = new Container("testDelete", new Editor(2, "object_test"), new Editor(3, "editor_test"));
+ doInsert(c);
+ doDelete(c);
+ }
+
+ public void testRead()
+ {
+ Container c = new Container("testRead", new Editor(2, "object_test"), new Editor(3, "editor_test"));
+ doInsert(c);
+
+ Identity oid = broker.serviceIdentity().buildIdentity(c);
+ Container read = (Container) broker.getObjectByIdentity(oid);
+ assertEquals(c, read);
+
+ broker.clearCache();
+ read = (Container) broker.getObjectByIdentity(oid);
+ assertEquals(c, read);
+
+ doDelete(c);
+ }
+
+ public void testQuery()
+ {
+ Container c = new Container("testQuery", new Editor(2, "object_test"), new Editor(3, "editor_test"));
+ doInsert(c);
+
+ Criteria crit = new Criteria().addEqualTo("id", c.getId());
+ Query q = QueryFactory.newQuery(Container.class, crit);
+ Container read = (Container) broker.getObjectByQuery(q);
+ assertEquals(c, read);
+
+ broker.clearCache();
+ read = (Container) broker.getObjectByQuery(q);
+ assertEquals(c, read);
+
+ doDelete(c);
+ }
+
+ public void testUpdate()
+ {
+ Container c = new Container("testUpdate", new Editor(2, "object_test"), new Editor(3, "editor_test"));
+ doInsert(c);
+
+ broker.beginTransaction();
+ c.setName(getName() + "_update_1");
+ c.getEditor().str = c.getEditor().str + "_update_1";
+ ((Editor) c.getTarget()).str = ((Editor) c.getTarget()).str + "_update_1";
+ broker.store(c);
+ broker.commitTransaction();
+
+ Identity oid = broker.serviceIdentity().buildIdentity(c);
+ Container read = (Container) broker.getObjectByIdentity(oid);
+ assertEquals(c, read);
+
+ broker.clearCache();
+ read = (Container) broker.getObjectByIdentity(oid);
+ assertEquals(c, read);
+
+ broker.clearCache();
+ broker.beginTransaction();
+ c = read;
+ c.setName(getName() + "_update_2");
+ c.getEditor().str = c.getEditor().str + "_update_2";
+ ((Editor) c.getTarget()).str = ((Editor) c.getTarget()).str + "_update_2";
+ broker.store(c);
+ broker.commitTransaction();
+
+ broker.clearCache();
+ read = (Container) broker.getObjectByIdentity(oid);
+ assertEquals(c, read);
+
+ doDelete(c);
+ }
+
+ void doInsert(Container c)
+ {
+ broker.beginTransaction();
+ broker.store(c);
+ broker.commitTransaction();
+ }
+
+ void doDelete(Container c)
+ {
+ broker.beginTransaction();
+ broker.delete(c);
+ broker.commitTransaction();
+ }
+
+ public static class Container implements Serializable
+ {
+ private Integer id;
+ private String name;
+ private Object target;
+ private Editor editor;
+
+ public Container()
+ {
+ }
+
+ public Container(String name, Object target, Editor editor)
+ {
+ this.name = name;
+ this.target = target;
+ this.editor = editor;
+ }
+
+ public Integer getId()
+ {
+ return id;
+ }
+
+ public void setId(Integer id)
+ {
+ this.id = id;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public Object getTarget()
+ {
+ return target;
+ }
+
+ public void setTarget(Object target)
+ {
+ this.target = target;
+ }
+
+ public Editor getEditor()
+ {
+ return editor;
+ }
+
+ public void setEditor(Editor editor)
+ {
+ this.editor = editor;
+ }
+
+ public boolean equals(Object obj)
+ {
+ return EqualsBuilder.reflectionEquals(this, obj);
+ }
+
+ public String toString()
+ {
+ return ToStringBuilder.reflectionToString(this);
+ }
+ }
+
+ public static class Editor implements Serializable
+ {
+ String str;
+ int aInt;
+
+ public Editor(int aInt, String str)
+ {
+ this.aInt = aInt;
+ this.str = str;
+ }
+
+ public boolean equals(Object obj)
+ {
+ return EqualsBuilder.reflectionEquals(this, obj);
+ }
+
+ public String toString()
+ {
+ return ToStringBuilder.reflectionToString(this);
+ }
+ }
+}
Added: db/ojb/trunk/src/test/org/apache/ojb/broker/UnwrapHelperTest.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/broker/UnwrapHelperTest.java?rev=422225&view=auto
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/broker/UnwrapHelperTest.java (added)
+++ db/ojb/trunk/src/test/org/apache/ojb/broker/UnwrapHelperTest.java Sat Jul 15 07:09:47 2006
@@ -0,0 +1,171 @@
+package org.apache.ojb.broker;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * 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.
+ */
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+
+import org.apache.ojb.broker.platforms.Platform;
+import org.apache.ojb.broker.platforms.PlatformHsqldbImpl;
+import org.apache.ojb.broker.util.ClassHelper;
+import org.apache.ojb.broker.util.UnwrapHelper;
+import org.apache.ojb.junit.PBTestCase;
+
+/**
+ * Simple test for unwrap helper class.
+ *
+ * @version $Id: $
+ */
+public class UnwrapHelperTest extends PBTestCase
+{
+ private UnwrapHelper helper;
+ private String statementClassName = "org.hsqldb.jdbc.jdbcPreparedStatement";
+ private String connectionClassName = "org.hsqldb.jdbc.jdbcConnection";
+ private String selectExample = "select 1 from OJB_HL_SEQ";
+
+ public static void main(String[] args)
+ {
+ String[] arr = {UnwrapHelperTest.class.getName()};
+ junit.textui.TestRunner.main(arr);
+ }
+
+ public UnwrapHelperTest(String name)
+ {
+ super(name);
+ }
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ helper = new UnwrapHelper();
+ }
+
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+ public void testAddPattern()
+ {
+ int length = helper.getUnwrapPatterns().length;
+ Object[] pattern = helper.getUnwrapPatterns()[0];
+ helper.addUnwrapPattern(pattern);
+ helper.addUnwrapPattern(new Object[][]{null, null, null, null, null, null, null});
+ //System.out.println("## " + helper.toString());
+ assertEquals(length + 2, helper.getUnwrapPatterns().length);
+ }
+
+ public void testUnwrapConnection() throws Exception
+ {
+ Platform pf = broker.serviceConnectionManager().getSupportedPlatform();
+ if(!PlatformHsqldbImpl.class.isAssignableFrom(pf.getClass()))
+ {
+ return;
+ }
+ Connection con = broker.serviceConnectionManager().getConnection();
+ Class target = ClassHelper.getClass(connectionClassName);
+ Connection result = helper.unwrapConnection(target, con);
+ assertNotNull(result);
+ assertTrue(target.isAssignableFrom(result.getClass()));
+ }
+
+ public void testUnwrapStatement() throws Exception
+ {
+ Platform pf = broker.serviceConnectionManager().getSupportedPlatform();
+ if(!PlatformHsqldbImpl.class.isAssignableFrom(pf.getClass()))
+ {
+ return;
+ }
+ Connection con = broker.serviceConnectionManager().getConnection();
+ PreparedStatement ps = con.prepareStatement(selectExample);
+ Class target = ClassHelper.getClass(statementClassName);
+ PreparedStatement result = helper.unwrapStatement(target, ps);
+ assertNotNull(result);
+ assertTrue(target.isAssignableFrom(result.getClass()));
+ }
+
+ /**
+ * Test useful for development.
+ */
+ public void testUnwrapLoop() throws Exception
+ {
+ Platform pf = broker.serviceConnectionManager().getSupportedPlatform();
+ if(!PlatformHsqldbImpl.class.isAssignableFrom(pf.getClass()))
+ {
+ return;
+ }
+ Connection con = broker.serviceConnectionManager().getConnection();
+ PreparedStatement ps = con.prepareStatement(selectExample);
+ Class targetC = ClassHelper.getClass(connectionClassName);
+ Class targetS = ClassHelper.getClass(statementClassName);
+ int loops = 5000;
+ long t = System.currentTimeMillis();
+ for(int i = 0;i<loops;i++)
+ {
+ Connection resultC = helper.unwrapConnection(targetC, con);
+ assertNotNull(resultC);
+ PreparedStatement resultS = helper.unwrapStatement(targetS, ps);
+ assertNotNull(resultS);
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println("Unwarp " + loops + " con/stmt (optimized mode): " + t + " ms");
+
+ Object[] pattern = helper.getUnwrapPatterns()[0];
+ helper.addUnwrapPattern(pattern);
+ helper.addUnwrapPattern(new Object[][]{null, null, null, null, null, null, null});
+ //System.out.println("Patterns: " + helper);
+
+ t = System.currentTimeMillis();
+ for(int i = 0;i<loops;i++)
+ {
+ Connection resultC = helper.unwrapConnection(targetC, con);
+ assertNotNull(resultC);
+ PreparedStatement resultS = helper.unwrapStatement(targetS, ps);
+ assertNotNull(resultS);
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println("Unwarp " + loops + " con/stmt (optimized mode): " + t + " ms");
+
+
+ helper = new UnwrapHelper(true, false);
+ t = System.currentTimeMillis();
+ for(int i = 0;i<loops;i++)
+ {
+ Connection resultC = helper.unwrapConnection(targetC, con);
+ assertNotNull(resultC);
+ PreparedStatement resultS = helper.unwrapStatement(targetS, ps);
+ assertNotNull(resultS);
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println("Unwarp " + loops + " con/stmt (search all patterns): " + t + " ms");
+
+ pattern = helper.getUnwrapPatterns()[0];
+ helper.addUnwrapPattern(pattern);
+ helper.addUnwrapPattern(new Object[][]{null, null, null, null, null, null, null});
+ //System.out.println("Patterns: " + helper);
+
+ t = System.currentTimeMillis();
+ for(int i = 0;i<loops;i++)
+ {
+ Connection resultC = helper.unwrapConnection(targetC, con);
+ assertNotNull(resultC);
+ PreparedStatement resultS = helper.unwrapStatement(targetS, ps);
+ assertNotNull(resultS);
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println("Unwarp " + loops + " con/stmt (search all patterns): " + t + " ms");
+ }
+}
Added: db/ojb/trunk/src/test/org/apache/ojb/performance/PerfRunner.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/performance/PerfRunner.java?rev=422225&view=auto
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/performance/PerfRunner.java (added)
+++ db/ojb/trunk/src/test/org/apache/ojb/performance/PerfRunner.java Sat Jul 15 07:09:47 2006
@@ -0,0 +1,213 @@
+package org.apache.ojb.performance;
+
+/* Copyright 2002-2005 The Apache Software Foundation
+ *
+ * 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.
+ */
+
+
+/**
+ * Derivate this class to implement a test instance for the performance test.
+ *
+ * @version $Id: PerfRunner.java 366953 2006-01-08 01:27:44 +0100 (So, 08 Jan 2006) arminw $
+ */
+class PerfRunner
+{
+ private final String PREFIX_LOG = "[" + this.getClass().getName() + "] ";
+
+ /**
+ * testTimes[0] startTime/test length
+ * testTimes[1] inserting times
+ * testTimes[2] fetching times
+ * testTimes[3] fetching repeat times
+ * testTimes[4] get by Identity times
+ * testTimes[5] updating times
+ * testTimes[6] deleting times
+ */
+ private long[] testTimes;
+ private ThreadGroup threadGroup;
+ private PerfMain perfMain;
+ private long perfTestId;
+ private boolean checked;
+ private boolean isValid;
+
+ /**
+ * The threads that are executing.
+ */
+ private Thread threads[] = null;
+ private Class testClass;
+ private PerfTest test;
+
+
+ public PerfRunner(ThreadGroup group, Class perfTestClass)
+ {
+ this.perfTestId = System.currentTimeMillis();
+ this.checked = false;
+ this.testClass = perfTestClass;
+ // create a tmp test instance
+ this.test = createTest();
+ this.threadGroup = group;
+ this.isValid = true;
+ }
+
+ private PerfTest createTest()
+ {
+ try
+ {
+ PerfTest result = (PerfTest) testClass.newInstance();
+ result.setPerfRunner(this);
+ return result;
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ throw new RuntimeException("Can't create test instance: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the name of the test
+ */
+ public String testName()
+ {
+ return test.testName();
+ }
+
+ private void checkApi() throws Exception
+ {
+ String name = testName() + "_Pre_Test_Object";
+ PerfArticle article = test.getPreparedPerfArticle(name);
+ PerfArticle[] arr = new PerfArticle[]{article};
+ test.insertNewArticles(arr);
+ test.readArticlesByCursor(name);
+ test.updateArticles(arr);
+ test.deleteArticles(arr);
+ checked = true;
+ }
+
+ /**
+ * Interrupt the running threads.
+ */
+ protected void interruptThreads()
+ {
+ if (threads != null)
+ {
+ for (int i = 0; i < threads.length; i++)
+ {
+ threads[i].interrupt();
+ }
+ }
+ PerfMain.printer().println("## Test failed! ##");
+ PerfMain.printer().println("## Test failed! ##");
+ }
+
+ /**
+ * Run the threads.
+ */
+ protected void runTestHandles(final PerfTest[] runnables)
+ {
+ if (runnables == null)
+ {
+ throw new IllegalArgumentException("runnables is null");
+ }
+ threads = new Thread[runnables.length];
+ for (int i = 0; i < threads.length; i++)
+ {
+ threads[i] = new Thread(threadGroup, runnables[i]);
+ }
+ for (int i = 0; i < threads.length; i++)
+ {
+ threads[i].start();
+ }
+ try
+ {
+ for (int i = 0; i < threads.length; i++)
+ {
+ threads[i].join();
+ }
+ }
+ catch (InterruptedException ignore)
+ {
+ PerfMain.printer().println(PREFIX_LOG + "Thread join interrupted.");
+ }
+ }
+
+ public void performTest()
+ {
+ try
+ {
+ // prepare tmp used test
+ test.init();
+
+ if (!checked)
+ {
+ checkApi();
+ //PerfMain.printer().println("# PerfTest: " + testName() + " # ");
+ }
+
+ int objectCount;
+ int objectCountAfter;
+
+ testTimes = new long[7];
+
+ objectCount = test.articleCount();
+
+ // now we start the test threads
+ PerfTest[] perfHandles = new PerfTest[PerfMain.getConcurrentThreads()];
+ for (int i = 0; i < PerfMain.getConcurrentThreads(); i++)
+ {
+ perfHandles[i] = createTest();
+ }
+ runTestHandles(perfHandles);
+
+ // end of test threads
+ objectCountAfter = test.articleCount();
+ perfMain.addPeriodResult(testName(), testTimes, isValid);
+ perfMain.addConsistentResult(testName(), objectCount, objectCountAfter);
+
+ // tear down tmp used test
+ test.tearDown();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ perfMain.registerException(PREFIX_LOG, e);
+ }
+ }
+
+ public void registerException(String causer, Exception e)
+ {
+ this.isValid = false;
+ perfMain.registerException(causer, e);
+ }
+
+ public synchronized void addTime(short position, long time)
+ {
+ testTimes[position] += time;
+ }
+
+ public void registerPerfMain(PerfMain aPerfMain)
+ {
+ this.perfMain = aPerfMain;
+ }
+
+ public ThreadGroup getThreadGroup()
+ {
+ return threadGroup;
+ }
+
+ public long getPerfTestId()
+ {
+ return perfTestId;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org