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/03/11 02:03:49 UTC

svn commit: r384976 - in /db/ojb/branches/OJB_1_0_RELEASE/src: java/org/apache/ojb/broker/util/UnwrapHelper.java test/org/apache/ojb/broker/UnwrapHelperTest.java

Author: arminw
Date: Fri Mar 10 17:03:47 2006
New Revision: 384976

URL: http://svn.apache.org/viewcvs?rev=384976&view=rev
Log:
initial check in

Added:
    db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/UnwrapHelper.java
    db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/UnwrapHelperTest.java

Added: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/UnwrapHelper.java
URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/UnwrapHelper.java?rev=384976&view=auto
==============================================================================
--- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/UnwrapHelper.java (added)
+++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/util/UnwrapHelper.java Fri Mar 10 17:03:47 2006
@@ -0,0 +1,284 @@
+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 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.PreparedStatement} instances of connection-pool libraries,
+ * application server and other.
+ *
+ * @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;
+    public static final Object[] EMPTY_ARG = new Object[]{};
+    public static final Class[] PARAM_TYPE_EMPTY = 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][5] object array. The following arguments will be expected:
+     * <ul>
+     * <li>unwrapInfo[i][0] = the vendor, product name as {@link String}</li>
+     *
+     * <li>unwrapInfo[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>unwrapInfo[i][2] = use {@link #PARAM_TYPE_EMPTY} if a no-arg method call is needed, otherwise
+     * specify the argument type class array (at runtime)</li>
+     * <li>unwrapInfo[i][3] = the name of the method/field to lookup the wrapped connection
+     * as {@link String}</li>
+     *
+     * <li>unwrapInfo[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>unwrapInfo[i][5] = use {@link #PARAM_TYPE_EMPTY} if a no-arg method call is needed, otherwise
+     * specify the argument type class array (at runtime)</li>
+     * <li>unwrapInfo[i][6] = the name of the method/field to unwrap the statement</li>
+     * </ul>
+     * Example:
+     * <pre>
+     * protected static Object[][] unwrapInfo = {
+     * {"common-DBCP", TYPE_METHOD, PARAM_TYPE_EMPTY, "getInnermostDelegate", TYPE_METHOD, PARAM_TYPE_EMPTY, "getInnermostDelegate"},
+     * {"enhydra.XAPool", TYPE_FIELD, null, "con", TYPE_FIELD, null, "ps"},
+     * ....
+     * </pre>
+     */
+    protected Object[][] unwrapInfo = {
+        {"common-DBCP", TYPE_METHOD, PARAM_TYPE_EMPTY, "getInnermostDelegate", TYPE_METHOD, PARAM_TYPE_EMPTY, "getInnermostDelegate"},
+        {"JBoss", TYPE_METHOD, PARAM_TYPE_EMPTY, "getUnderlyingConnection", TYPE_METHOD, PARAM_TYPE_EMPTY, "getUnderlyingStatement"},
+        {"enhydra.XAPool", TYPE_FIELD, null, "con", TYPE_FIELD, null, "ps"},
+        {"BEA Weblogic", TYPE_METHOD, PARAM_TYPE_EMPTY, "getVendorConnection", null, null, null},
+        {"p6spy", TYPE_METHOD, PARAM_TYPE_EMPTY, "getJDBC", TYPE_METHOD, PARAM_TYPE_EMPTY, "getJDBC"}
+    };
+
+    /**
+     * Add a new unwrap pattern. The object array of length 7 have to be
+     * the following arguments:
+     * <ul>
+     * <li>pattern[0] = the vendor, product name as {@link String}</li>
+     *
+     * <li>pattern[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>pattern[2] = use {@link #PARAM_TYPE_EMPTY} if a no-arg method call is needed, otherwise
+     * specify the argument type class array (at runtime)</li>
+     * <li>pattern[3] = the name of the method/field to lookup the wrapped connection
+     * as {@link String}</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>
+     * <li>pattern[5] = use {@link #PARAM_TYPE_EMPTY} if a no-arg method call is needed, otherwise
+     * specify the argument type class array (at runtime)</li>
+     * <li>pattern[6] = the name of the method/field to unwrap the statement as {@link String}</li>
+     * </ul>
+     * Here is an example how to use this method:
+     * <pre>
+     * Object test = new Object[]{"common-DBCP", TYPE_METHOD, PARAM_TYPE_EMPTY, "getInnermostDelegate",
+     * TYPE_METHOD, PARAM_TYPE_EMPTY, "getInnermostDelegate"};
+     * unwarpHelper.addUnwrapPattern(test);
+     * </pre>
+     *
+     * @param pattern The unwrap pattern array.
+     */
+    public void addUnwrapPattern(Object[] pattern)
+    {
+        Object[][] tmp = new Object[][]{pattern};
+        unwrapInfo = (Object[][]) ArrayUtils.addAll(unwrapInfo, tmp);
+    }
+
+    /** Return the current unwrap patterns. */
+    public Object[][] getUnwrapPatterns()
+    {
+        return unwrapInfo;
+    }
+
+    protected Object genericUnwrap(final Class classToMatch, final Object toUnwrap, int type)
+    {
+        if(classToMatch == null)
+        {
+            return null;
+        }
+
+        Object unwrapped = null;
+        if(classToMatch.isAssignableFrom(toUnwrap.getClass()))
+        {
+            return toUnwrap;
+        }
+        int i = 0;
+        try
+        {
+            for(; i < unwrapInfo.length; i++)
+            {
+                Object[] info = unwrapInfo[i];
+                if(type == UNWARP_CONNECTION && info[3] != null)
+                {
+                    unwrapped = reflectObject(toUnwrap, info[1].equals(TYPE_METHOD), (Class[]) info[2], (String) info[3]);
+                }
+                else if(type == UNWARP_STATEMENT && info[6] != null)
+                {
+                    unwrapped = reflectObject(toUnwrap, info[4].equals(TYPE_METHOD), (Class[]) info[5], (String) info[6]);
+                }
+                if(unwrapped != null)
+                {
+                    if(classToMatch.isAssignableFrom(unwrapped.getClass()))
+                    {
+                        // Bingo!
+                    }
+                    else
+                    {
+                        // When using e.g. both DBCP and P6Spy we have to recursively unwrap
+                        unwrapped = genericUnwrap(classToMatch, unwrapped, type);
+                    }
+                    break;
+                }
+            }
+        }
+        catch(Exception e)
+        {
+            //e.printStackTrace();
+            // ignore
+            if(log.isDebugEnabled())
+            {
+                if(type == UNWARP_CONNECTION)
+                {
+                    log.debug("Unwrap of connection failed using unwrap rule for " + unwrapInfo[i][0] + " connections", e);
+                }
+                else
+                {
+                    log.debug("Unwrap of prepared stmt failed using unwrap rule for " + unwrapInfo[i][0] + " statements", e);
+                }
+            }
+        }
+        return unwrapped;
+    }
+
+    private Object reflectObject(Object source, boolean methodType, Class[] paramType, 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);
+                }
+                unwrapped = method.invoke(source, EMPTY_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(Class target, 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(Class target, 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(Class target, PreparedStatement source)
+    {
+        PreparedStatement result = (PreparedStatement) 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;
+    }
+
+    public String toString()
+    {
+        ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
+        buf.append("Supported unwrap pattern: ");
+        for(int i = 0; i < unwrapInfo.length; i++)
+        {
+            buf.append(ArrayUtils.toString(unwrapInfo[i]));
+        }
+        return buf.toString();
+    }
+}

Added: db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/UnwrapHelperTest.java
URL: http://svn.apache.org/viewcvs/db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/UnwrapHelperTest.java?rev=384976&view=auto
==============================================================================
--- db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/UnwrapHelperTest.java (added)
+++ db/ojb/branches/OJB_1_0_RELEASE/src/test/org/apache/ojb/broker/UnwrapHelperTest.java Fri Mar 10 17:03:47 2006
@@ -0,0 +1,125 @@
+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);
+        //System.out.println("## " + helper.toString());
+        assertEquals(length + 1, 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 XXXtestUnwrapLoop() 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);
+        long t = System.currentTimeMillis();
+        int loops = 5000;
+        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: " + t + " ms");
+    }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org