openjpa-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Albert Lee <allee8...@gmail.com>
Subject Re: svn commit: r743396 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/ openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-lib/src/main/java/org/apach
Date Wed, 11 Feb 2009 20:26:38 GMT
Using the fetch plan's lock timeout field for 2 different usage (LockTimeout
and QueryTimeout) is implementation.

>From functional point of view, the getQueryTimeout() is the correct call to
get the associate "javax.persistence.query.timeout"  property value. You
never know if this may change in the future that 2 different values will be
used, for whatever reason. At that time this test will fail.

I think we need to change to test the proper value.

Thanks,
Albert Lee.

On Wed, Feb 11, 2009 at 2:19 PM, Pinaki Poddar <ppoddar@apache.org> wrote:

>
> Yes, ideally. But query fetch plan's lock timeout is currently interpreted
> as
> JDBC statement's query timeout during select operation.
> FetchPlan/FetchConfiguration currently is not holding two separate timeout
> values for locking and selection operation.
> May be OPENJPA-878 should consider such a change.
>
>
> Donald Woods wrote:
> >
> > In
> >
> openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/conf/TestQueryHints.java
> >
> > Is this right?
> > +    public void testJPAHintSetsFetchPlan() {
> > +        String jpaKey = "javax.persistence.query.timeout";
> > +        query.setHint(jpaKey, 5671);
> > +        assertEquals(5671, query.getFetchPlan().getLockTimeout());
> > +    }
> > +
> >
> > Shouldn't it be fetching the QueryTimeout instead?
> > +    public void testJPAHintSetsFetchPlan() {
> > +        String jpaKey = "javax.persistence.query.timeout";
> > +        query.setHint(jpaKey, 5671);
> > +        assertEquals(5671, query.getFetchPlan().getQueryTimeout());
> > +    }
> > +
> >
> >
> > -Donald
> >
> > ppoddar@apache.org wrote:
> >> Author: ppoddar
> >> Date: Wed Feb 11 16:57:26 2009
> >> New Revision: 743396
> >>
> >> URL: http://svn.apache.org/viewvc?rev=743396&view=rev
> >> Log:
> >> OPENJPA-900: Consolidate Query Hint related processing. As a byproduct,
> >> support new JPA 2.0 getHins() and getSupportedHints().
> >>
> >> Added:
> >>
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/Reflectable.java
> >>
> >>
> openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/conf/TestQueryHints.java
> >>
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/HintHandler.java
> >> Modified:
> >>
> >>
> openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCProductDerivation.java
> >>
> >>
> openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java
> >>
> >>
> openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java
> >>
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/AbstractProductDerivation.java
> >>
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivation.java
> >>
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java
> >>
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java
> >>
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
> >>
> >>
> openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties
> >>
> >>
> openjpa/trunk/openjpa-slice/src/main/java/org/apache/openjpa/slice/ProductDerivation.java
> >>
> >> Modified:
> >>
> openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCProductDerivation.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCProductDerivation.java?rev=743396&r1=743395&r2=743396&view=diff
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCProductDerivation.java
> >> (original)
> >> +++
> >>
> openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCProductDerivation.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -18,11 +18,14 @@
> >>   */
> >>  package org.apache.openjpa.jdbc.conf;
> >>
> >> +import java.util.Collections;
> >>  import java.util.Map;
> >> +import java.util.Set;
> >>
> >>  import org.apache.openjpa.conf.BrokerFactoryValue;
> >>  import org.apache.openjpa.conf.OpenJPAProductDerivation;
> >>  import org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory;
> >> +import org.apache.openjpa.jdbc.sql.OracleDictionary;
> >>  import org.apache.openjpa.lib.conf.AbstractProductDerivation;
> >>  import org.apache.openjpa.lib.conf.ConfigurationProvider;
> >>
> >> @@ -48,4 +51,9 @@
> >>          }
> >>          return false;
> >>      }
> >> +
> >> +    @Override
> >> +    public Set<String> getSupportedQueryHints() {
> >> +        return Collections.singleton(OracleDictionary.SELECT_HINT);
> >> +    }
> >>  }
> >>
> >> Modified:
> >>
> openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java?rev=743396&r1=743395&r2=743396&view=diff
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java
> >> (original)
> >> +++
> >>
> openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -21,13 +21,18 @@
> >>  import java.lang.reflect.AccessibleObject;
> >>  import java.lang.reflect.Field;
> >>  import java.lang.reflect.InvocationTargetException;
> >> +import java.lang.reflect.Member;
> >>  import java.lang.reflect.Method;
> >>  import java.lang.reflect.Modifier;
> >>  import java.security.AccessController;
> >> +import java.util.Collections;
> >> +import java.util.Set;
> >> +import java.util.TreeSet;
> >>
> >>  import org.apache.commons.lang.StringUtils;
> >>  import org.apache.openjpa.lib.util.J2DoPrivHelper;
> >>  import org.apache.openjpa.lib.util.Localizer;
> >> +import org.apache.openjpa.lib.util.Reflectable;
> >>  import org.apache.openjpa.util.GeneralException;
> >>  import org.apache.openjpa.util.UserException;
> >>
> >> @@ -754,4 +759,166 @@
> >>      public static void set(Object target, Method setter, short value) {
> >>          set(target, setter, new Short(value));
> >>      }
> >> +
> >> +    /**
> >> +     * Gets all bean-style property names of the given Class or its
> >> superclass.
> >> +     * A bean-style property 'abc' exists in Class C iff C has declared
> >> +     * following pair of methods:
> >> +     *   public void setAbc(Y y) or public C setAbc(Y y)
> >> +     *   public Y getAbc();
> >> +     *
> >> +     * If a getter property is annotated with {@link Reflectable}, then
> >> +     * it is ignored.
> >> +     *
> >> +     */
> >> +    public static Set<String> getBeanStylePropertyNames(Class c) {
> >> +        if (c == null)
> >> +            return Collections.EMPTY_SET;
> >> +        Method[] methods = c.getMethods();
> >> +        if (methods == null || methods.length < 2)
> >> +            return Collections.EMPTY_SET;
> >> +        Set<String> result = new TreeSet<String>();
> >> +        for (Method m : methods) {
> >> +            if (m.getName().startsWith("get")) {
> >> +                if (!canReflect(m))
> >> +                    continue;
> >> +                String prop = StringUtils.capitalize(m.getName()
> >> +                    .substring("get".length()));
> >> +                Class rtype = m.getReturnType();
> >> +                try {
> >> +                  Method setter = c.getMethod("set"+prop, new
> >> Class[]{rtype});
> >> +                  if (setter.getReturnType() == void.class ||
> >> +                      setter.getReturnType().isAssignableFrom(c))
> >> +                  result.add(prop);
> >> +                } catch (NoSuchMethodException e) {
> >> +
> >> +                }
> >> +            }
> >> +        }
> >> +        return result;
> >> +    }
> >> +
> >> +    /**
> >> +     * Gets all public field names of the given Class.
> >> +     *
> >> +     */
> >> +    public static Set<String> getPublicFieldNames(Class c) {
> >> +        if (c == null)
> >> +            return Collections.EMPTY_SET;
> >> +        Field[] fields = c.getFields();
> >> +        if (fields == null || fields.length == 0)
> >> +            return Collections.EMPTY_SET;
> >> +        Set<String> result = new TreeSet<String>();
> >> +        for (Field f : fields) {
> >> +            if (canReflect(f))
> >> +                result.add(f.getName());
> >> +        }
> >> +        return result;
> >> +    }
> >> +
> >> +    /**
> >> +     * Gets values of all field f the given class such that f exactly
> >> +     * match the given modifiers and are of given type (Object implies
> >> any type)
> >> +     * unless f is annotated as {@link Reflectable}.
> >> +     *
> >> +     */
> >> +    public static <T> Set<T> getFieldValues(Class c, int mods, Class<T>
> >> t){
> >> +        if (c == null)
> >> +            return Collections.EMPTY_SET;
> >> +        Field[] fields = c.getFields();
> >> +        if (fields == null || fields.length == 0)
> >> +            return Collections.EMPTY_SET;
> >> +        Set<T> result = new TreeSet<T>();
> >> +        for (Field f : fields) {
> >> +            if (mods == f.getModifiers()
> >> +            && (t == Object.class || t.isAssignableFrom(f.getType()))
> >> +            && canReflect(f)) {
> >> +                try {
> >> +                    result.add((T)f.get(null));
> >> +                } catch (IllegalArgumentException e) {
> >> +                } catch (IllegalAccessException e) {
> >> +                }
> >> +            }
> >> +        }
> >> +        return result;
> >> +    }
> >> +
> >> +    /**
> >> +     * Affirms if the given member is selected for reflection. The
> >> decision is
> >> +     * based on the following truth table on both the class-level and
> >> +     * member-level annotation (null annotation represents MAYBE)
> >> +     *
> >> +     * Class   member
> >> +     * MAYBE   MAYBE   YES
> >> +     * MAYBE   YES     YES
> >> +     * MAYBE   NO      NO
> >> +     *
> >> +     * YES     MAYBE   YES
> >> +     * YES     YES     YES
> >> +     * YES     NO      NO
> >> +     *
> >> +     * NO      YES     YES
> >> +     * NO      MAYBE   NO
> >> +     * NO      NO      NO
> >> +     *
> >> +    */
> >> +    static boolean canReflect(Reflectable cls, Reflectable member) {
> >> +        if (cls == null || cls.value()) {
> >> +            return member == null || member.value() == true;
> >> +        } else {
> >> +            return member != null && member.value() == true;
> >> +        }
> >> +    }
> >> +
> >> +    /**
> >> +     * Affirms if the original declaration the given field is annotated
> >> +     * for reflection.
> >> +     */
> >> +    static boolean canReflect(Field field) {
> >> +        Class cls = field.getDeclaringClass();
> >> +        return
> >> canReflect((Reflectable)cls.getAnnotation(Reflectable.class),
> >> +            field.getAnnotation(Reflectable.class));
> >> +    }
> >> +
> >> +    /**
> >> +     * Affirms if the original declaration the given method is
> annotated
> >> +     * for reflection.
> >> +     */
> >> +    static boolean canReflect(Method method) {
> >> +        Class cls = getDeclaringClass(method);
> >> +        if (cls != method.getDeclaringClass())
> >> +            method = getDeclaringMethod(cls, method);
> >> +        return
> >> canReflect((Reflectable)cls.getAnnotation(Reflectable.class),
> >> +            method.getAnnotation(Reflectable.class));
> >> +    }
> >> +
> >> +    /**
> >> +     * Gets the declaring class of the given method signature but also
> >> checks
> >> +     * if the method is declared in an interface. If yes, then returns
> >> the
> >> +     * interface.
> >> +     */
> >> +    public static Class getDeclaringClass(Method m) {
> >> +        if (m == null)
> >> +            return null;
> >> +        Class cls = m.getDeclaringClass();
> >> +        Class[] intfs =  cls.getInterfaces();
> >> +        for (Class intf : intfs) {
> >> +            if (getDeclaringMethod(intf, m) != null)
> >> +                cls = intf;
> >> +        }
> >> +        return cls;
> >> +    }
> >> +
> >> +    /**
> >> +     * Gets the method in the given class that has the same signature
> of
> >> the
> >> +     * given method, if exists. Otherwise, null.
> >> +     */
> >> +    public static Method getDeclaringMethod(Class c, Method m) {
> >> +        try {
> >> +            Method m0 = c.getMethod(m.getName(),
> m.getParameterTypes());
> >> +            return m0;
> >> +        } catch (Exception e) {
> >> +            return null;
> >> +        }
> >> +    }
> >>  }
> >>
> >> Modified:
> >>
> openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java?rev=743396&r1=743395&r2=743396&view=diff
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java
> >> (original)
> >> +++
> >>
> openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/Filters.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -247,12 +247,23 @@
> >>          if (type.isAssignableFrom(o.getClass()))
> >>              return o;
> >>
> >> -        // the only non-numeric conversions we do are to string, or
> from
> >> +        // the non-numeric conversions we do are to string, or from
> >>          // string/char to number, or calendar/date
> >> +        // String to Boolean
> >> +        // String to Integer
> >>          boolean num = o instanceof Number;
> >>          if (!num) {
> >>              if (type == String.class)
> >>                  return o.toString();
> >> +            else if (type == Boolean.class && o instanceof String)
> >> +                return Boolean.valueOf(o.toString());
> >> +            else if (type == Integer.class && o instanceof String)
> >> +                try {
> >> +                    return new Integer(o.toString());
> >> +                } catch (NumberFormatException e) {
> >> +                    throw new
> >> ClassCastException(_loc.get("cant-convert", o,
> >> +                        o.getClass(), type).getMessage());
> >> +                }
> >>              else if (type == Character.class) {
> >>                  String str = o.toString();
> >>                  if (str != null && str.length() == 1)
> >>
> >> Modified:
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/AbstractProductDerivation.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/AbstractProductDerivation.java?rev=743396&r1=743395&r2=743396&view=diff
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/AbstractProductDerivation.java
> >> (original)
> >> +++
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/AbstractProductDerivation.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -19,7 +19,9 @@
> >>  package org.apache.openjpa.lib.conf;
> >>
> >>  import java.io.File;
> >> +import java.util.Collections;
> >>  import java.util.List;
> >> +import java.util.Set;
> >>
> >>  /**
> >>   * Abstract no-op product derivation for easy extension.
> >> @@ -85,4 +87,8 @@
> >>
> >>      public void beforeConfigurationClose(Configuration conf) {
> >>      }
> >> +
> >> +    public Set<String> getSupportedQueryHints() {
> >> +        return Collections.EMPTY_SET;
> >> +    }
> >>  }
> >>
> >> Modified:
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivation.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivation.java?rev=743396&r1=743395&r2=743396&view=diff
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivation.java
> >> (original)
> >> +++
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivation.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -21,6 +21,7 @@
> >>  import java.io.File;
> >>  import java.io.IOException;
> >>  import java.util.List;
> >> +import java.util.Set;
> >>
> >>  /**
> >>   * Hooks for deriving products with additional functionality.
> >> @@ -157,4 +158,13 @@
> >>       * @since 0.9.7
> >>       */
> >>      public void beforeConfigurationClose(Configuration conf);
> >> +
> >> +
> >> +    /**
> >> +     * Return set of Query hint keys recognized by this receiver.
> >> +     *
> >> +     * @since 2.0.0
> >> +     */
> >> +    public Set<String> getSupportedQueryHints();
> >> +
> >>  }
> >>
> >> Modified:
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java?rev=743396&r1=743395&r2=743396&view=diff
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java
> >> (original)
> >> +++
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -29,6 +29,8 @@
> >>  import java.util.List;
> >>  import java.util.Map;
> >>  import java.util.MissingResourceException;
> >> +import java.util.Set;
> >> +import java.util.TreeSet;
> >>
> >>  import org.apache.commons.lang.StringUtils;
> >>  import org.apache.openjpa.lib.util.J2DoPrivHelper;
> >> @@ -434,6 +436,19 @@
> >>                  collection.add(fqLoc);
> >>          }
> >>      }
> >> +
> >> +
> >> +    public static Set<String> getSupportedQueryHints() {
> >> +        Set<String> result = new TreeSet<String>();
> >> +        // most specific to least
> >> +        for (int i = _derivations.length - 1; i >= 0; i--) {
> >> +            Set<String> members =
> >> _derivations[i].getSupportedQueryHints();
> >> +            if (members != null || !members.isEmpty())
> >> +                result.addAll(members);
> >> +        }
> >> +        return result;
> >> +    }
> >> +
> >>
> >>      /**
> >>       * Compare {@link ProductDerivation}s.
> >>
> >> Added:
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/Reflectable.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/Reflectable.java?rev=743396&view=auto
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/Reflectable.java
> >> (added)
> >> +++
> >>
> openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/Reflectable.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -0,0 +1,25 @@
> >> +package org.apache.openjpa.lib.util;
> >> +
> >> +import static java.lang.annotation.ElementType.FIELD;
> >> +import static java.lang.annotation.ElementType.METHOD;
> >> +import static java.lang.annotation.ElementType.TYPE;
> >> +import static java.lang.annotation.RetentionPolicy.RUNTIME;
> >> +
> >> +import java.lang.annotation.Retention;
> >> +import java.lang.annotation.Target;
> >> +
> >> +/**
> >> + * Annotates a getter method or field so {@link Reflection reflection
> >> + * utility} to control whether the annotated member is recorded during
> >> scanning
> >> + * for bean-style method or field.
> >> + *
> >> + * @author Pinaki Poddar
> >> + *
> >> + * @since 2.0.0
> >> + *
> >> + */
> >> +@Target({TYPE, METHOD, FIELD})
> >> +@Retention(RUNTIME)
> >> +public @interface Reflectable {
> >> +    boolean value() default true;
> >> +}
> >>
> >> Added:
> >>
> openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/conf/TestQueryHints.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/conf/TestQueryHints.java?rev=743396&view=auto
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/conf/TestQueryHints.java
> >> (added)
> >> +++
> >>
> openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/conf/TestQueryHints.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -0,0 +1,167 @@
> >> +/*
> >> + * Licensed to the Apache Software Foundation (ASF) under one
> >> + * or more contributor license agreements.  See the NOTICE file
> >> + * distributed with this work for additional information
> >> + * regarding copyright ownership.  The ASF licenses this file
> >> + * to you 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.
> >> + */
> >> +package org.apache.openjpa.conf;
> >> +
> >> +import javax.persistence.EntityManager;
> >> +import javax.persistence.Query;
> >> +
> >> +import org.apache.openjpa.jdbc.sql.OracleDictionary;
> >> +import org.apache.openjpa.kernel.QueryHints;
> >> +import org.apache.openjpa.persistence.HintHandler;
> >> +import org.apache.openjpa.persistence.OpenJPAPersistence;
> >> +import org.apache.openjpa.persistence.OpenJPAQuery;
> >> +import org.apache.openjpa.persistence.test.SingleEMFTestCase;
> >> +
> >> +/**
> >> + * Tests JPA 2.0 API methods {@link Query#getSupportedHints()} and
> >> + * {@link Query#getHints()}.
> >> + *
> >> + * @author Pinaki Poddar
> >> + *
> >> + */
> >> +public class TestQueryHints extends SingleEMFTestCase {
> >> +    EntityManager em;
> >> +    OpenJPAQuery query;
> >> +
> >> +    public void setUp() {
> >> +       super.setUp((Object[])null);
> >> +       em = emf.createEntityManager();
> >> +       String sql = "select * from Person";
> >> +       query = OpenJPAPersistence.cast(em.createNativeQuery(sql));
> >> +    }
> >> +
> >> +    public void testSupportedHintsContainProductDerivationHints() {
> >> +        assertSupportedHint(OracleDictionary.SELECT_HINT, true);
> >> +    }
> >> +
> >> +    public void testSupportedHintsContainFetchPlanHints() {
> >> +        assertSupportedHint("openjpa.FetchPlan.LockTimeout", true);
> >> +    }
> >> +
> >> +    public void
> >> testSupportedHintsIgnoresSomeFetchPlanBeanStyleProperty() {
> >> +        assertSupportedHint("openjpa.FetchPlan.QueryResultCache",
> >> false);
> >> +    }
> >> +
> >> +    public void testSupportedHintsContainQueryProperty() {
> >> +        assertSupportedHint("openjpa.Subclasses", true);
> >> +    }
> >> +
> >> +    public void testSupportedHintsContainKernelQueryHints() {
> >> +        assertSupportedHint(QueryHints.HINT_IGNORE_PREPARED_QUERY,
> >> true);
> >> +    }
> >> +
> >> +    public void testSupportedHintsContainJPAQueryHints() {
> >> +        assertSupportedHint("javax.persistence.query.timeout", true);
> >> +    }
> >> +
> >> +    public void testUnrecognizedKeyIsIgnored() {
> >> +        String unrecognizedKey = "acme.org.hint.SomeThingUnknown";
> >> +        query.setHint(unrecognizedKey, "xyz");
> >> +        assertFalse(query.getHints().containsKey(unrecognizedKey));
> >> +
> >> assertNull(query.getFetchPlan().getDelegate().getHint(unrecognizedKey));
> >> +     }
> >> +
> >> +    public void testRecognizedKeyIsNotRecordedButAvailable() {
> >> +        String recognizedKey = "openjpa.some.derivation.hint";
> >> +        query.setHint(recognizedKey, "abc");
> >> +        assertFalse(query.getHints().containsKey(recognizedKey));
> >> +        assertEquals("abc",
> >> query.getFetchPlan().getDelegate().getHint(recognizedKey));
> >> +    }
> >> +
> >> +    public void testSupportedKeyIsRecordedAndAvailable() {
> >> +        String supportedKey = "openjpa.FetchPlan.FetchBatchSize";
> >> +        query.setHint(supportedKey, 42);
> >> +        assertTrue(query.getHints().containsKey(supportedKey));
> >> +        assertEquals(42, query.getFetchPlan().getFetchBatchSize());
> >> +    }
> >> +
> >> +    public void testSupportedKeyWrongValue() {
> >> +        String supportedKey = "openjpa.FetchPlan.FetchBatchSize";
> >> +        short goodValue = (short)42;
> >> +        float badValue = 57.9f;
> >> +        query.setHint(supportedKey, goodValue);
> >> +        assertTrue(query.getHints().containsKey(supportedKey));
> >> +        assertEquals(goodValue,
> >> query.getFetchPlan().getFetchBatchSize());
> >> +
> >> +        try {
> >> +            query.setHint(supportedKey, badValue);
> >> +            fail("Expected to fail to set " + supportedKey + " hint to
> "
> >> + badValue);
> >> +        } catch (IllegalArgumentException e) {
> >> +            // good
> >> +        }
> >> +    }
> >> +
> >> +    public void testSupportedKeyIntegerValueConversion() {
> >> +        String supportedKey = "openjpa.hint.OptimizeResultCount";
> >> +        String goodValue = "57";
> >> +        int badValue = -3;
> >> +        query.setHint(supportedKey, goodValue);
> >> +        assertTrue(query.getHints().containsKey(supportedKey));
> >> +        assertEquals(57,
> >> query.getFetchPlan().getDelegate().getHint(supportedKey));
> >> +
> >> +        try {
> >> +            query.setHint(supportedKey, badValue);
> >> +            fail("Expected to fail to set " + supportedKey + " hint to
> "
> >> + badValue);
> >> +        } catch (IllegalArgumentException e) {
> >> +            // good
> >> +        }
> >> +    }
> >> +
> >> +    public void testSupportedKeyBooleanValueConversion() {
> >> +        String supportedKey = QueryHints.HINT_IGNORE_PREPARED_QUERY;
> >> +        String goodValue = "true";
> >> +        query.setHint(supportedKey, goodValue);
> >> +        assertTrue(query.getHints().containsKey(supportedKey));
> >> +        assertEquals(true,
> >> query.getFetchPlan().getDelegate().getHint(supportedKey));
> >> +
> >> +        goodValue = "false";
> >> +        query.setHint(supportedKey, goodValue);
> >> +        assertTrue(query.getHints().containsKey(supportedKey));
> >> +        assertEquals(false,
> >> query.getFetchPlan().getDelegate().getHint(supportedKey));
> >> +    }
> >> +
> >> +    public void testJPAHintSetsFetchPlan() {
> >> +        String jpaKey = "javax.persistence.query.timeout";
> >> +        query.setHint(jpaKey, 5671);
> >> +        assertEquals(5671, query.getFetchPlan().getLockTimeout());
> >> +    }
> >> +
> >> +    public void testParts() {
> >> +        HintHandler.HintKeyComparator test = new
> >> HintHandler.HintKeyComparator();
> >> +        assertEquals(0, test.countDots("a"));
> >> +        assertEquals(1, test.countDots("a.b"));
> >> +        assertEquals(2, test.countDots("a.b.c"));
> >> +        assertEquals(3, test.countDots("a.b.c.d"));
> >> +        assertEquals(4, test.countDots("a.b.c.d."));
> >> +        assertEquals(1, test.countDots("."));
> >> +        assertEquals(0, test.countDots(""));
> >> +        assertEquals(0, test.countDots(null));
> >> +    }
> >> +
> >> +    void assertSupportedHint(String hint, boolean contains) {
> >> +        if (contains)
> >> +            assertTrue("Expeceted suppoerted hint [" + hint + "]",
> >> +                query.getSupportedHints().contains(hint));
> >> +        else
> >> +            assertFalse("Unexpeceted suppoerted hint [" + hint + "]",
> >> +                query.getSupportedHints().contains(hint));
> >> +    }
> >> +
> >> +
> >> +}
> >>
> >> Modified:
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java?rev=743396&r1=743395&r2=743396&view=diff
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java
> >> (original)
> >> +++
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -22,6 +22,7 @@
> >>  import javax.persistence.LockModeType;
> >>
> >>  import org.apache.openjpa.kernel.FetchConfiguration;
> >> +import org.apache.openjpa.lib.util.Reflectable;
> >>  import org.apache.openjpa.meta.FetchGroup;
> >>
> >>  /**
> >> @@ -88,6 +89,7 @@
> >>       *
> >>       * @since 1.0.0
> >>       */
> >> +    @Reflectable(false)
> >>      public boolean getQueryResultCacheEnabled();
> >>
> >>      /**
> >> @@ -102,6 +104,7 @@
> >>      /**
> >>       * @deprecated use {@link #getQueryResultCacheEnabled()} instead.
> >>       */
> >> +    @Reflectable(false)
> >>      public boolean getQueryResultCache();
> >>
> >>      /**
> >> @@ -293,5 +296,6 @@
> >>       * @deprecated cast to {@link FetchPlanImpl} instead. This
> >>       * method pierces the published-API boundary, as does the SPI cast.
> >>       */
> >> +    @Reflectable(false)
> >>      public org.apache.openjpa.kernel.FetchConfiguration getDelegate();
> >>  }
> >>
> >> Added:
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/HintHandler.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/HintHandler.java?rev=743396&view=auto
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/HintHandler.java
> >> (added)
> >> +++
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/HintHandler.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -0,0 +1,365 @@
> >> +package org.apache.openjpa.persistence;
> >> +
> >> +import static
> >> org.apache.openjpa.kernel.QueryHints.HINT_IGNORE_PREPARED_QUERY;
> >> +import static
> >> org.apache.openjpa.kernel.QueryHints.HINT_INVALIDATE_PREPARED_QUERY;
> >> +import static org.apache.openjpa.kernel.QueryHints.HINT_RESULT_COUNT;
> >> +
> >> +import java.lang.reflect.Method;
> >> +import java.lang.reflect.Modifier;
> >> +import java.util.Collections;
> >> +import java.util.Comparator;
> >> +import java.util.Map;
> >> +import java.util.Set;
> >> +import java.util.TreeMap;
> >> +import java.util.TreeSet;
> >> +
> >> +import org.apache.openjpa.conf.OpenJPAConfiguration;
> >> +import org.apache.openjpa.enhance.Reflection;
> >> +import org.apache.openjpa.kernel.FetchConfiguration;
> >> +import org.apache.openjpa.kernel.Filters;
> >> +import org.apache.openjpa.kernel.exps.AggregateListener;
> >> +import org.apache.openjpa.kernel.exps.FilterListener;
> >> +import org.apache.openjpa.lib.conf.ProductDerivation;
> >> +import org.apache.openjpa.lib.conf.ProductDerivations;
> >> +import org.apache.openjpa.lib.log.Log;
> >> +import org.apache.openjpa.lib.util.Localizer;
> >> +import org.apache.openjpa.lib.util.StringDistance;
> >> +
> >> +
> >> +/**
> >> + * Manages query hint keys and handles their values on behalf of a
> >> owning
> >> + * {@link QueryImpl}. Uses specific knowledge of hint keys declared in
> >> + * different parts of the system.
> >> + *
> >> + * This receiver collects hint keys from different parts of the system.
> >> The
> >> + * keys are implicitly or explicitly declared by several different
> >> mechanics.
> >> + * This receiver sets the values on behalf of a owning {@link
> QueryImpl}
> >> + * based on the its specific knowledge of these keys.
> >> + *
> >> + * The hint keys from following sources are collected and handled:
> >> + *
> >> + * 1. {@link org.apache.openjpa.kernel.QueryHints} interface declares
> >> hint keys
> >> + *    as public static final fields. These fields are collected by
> >> reflection.
> >> + *    The values are handled by invoking methods on the owning {@link
> >> QueryImpl}
> >> + *
> >> + * 2. Some hint keys are collected from bean-style property names of
> >> {@link
> >> + *    JDBCFetchPlan} by {@link
> >> Reflection#getBeanStylePropertyNames(Class)
> >> + *    reflection} and prefixed with <code>openjpa.FetchPlan</code>.
> >> + *    Their values are used to set the corresponding property of {@link
> >> + *    FetchPlan} via {@link #hintToSetter(FetchPlan, String, Object)
> >> reflection}
> >> + *
> >> + * 3. Currently defined <code>javax.persistence.*</code> hint keys have
> >> + *    a equivalent counterpart to one of these FetchPlan keys.
> >> + *    The JPA keys are mapped to equivalent FetchPlan hint keys.
> >> + *
> >> + * 4. Some keys directly invoke setters or add listeners to the owning
> >> + *    {@link QueryImpl}. These hint keys are statically declared in
> >> + *    this receiver itself.
> >> + *
> >> + * 5. ProductDerivation may introduce their own query hint keys via
> >> {@link
> >> + *    ProductDerivation#getSupportedQueryHints()}. Their values are set
> >> in the
> >> + *    {@link FetchConfiguration#setHint(String, Object)}
> >> + *
> >> + *  A hint key is classified into one of the following three
> categories:
> >> + *
> >> + *  1. Supported: A key is known to this receiver as collected from
> >> different
> >> + *     parts of the system. The value of a supported key is recorded
> and
> >> + *     available via {@link #getHints()} method.
> >> + *  2. Recognized: A key is not known to this receiver but has a prefix
> >> which
> >> + *     is known to this receiver. The value of a recognized key is not
> >> recorded
> >> + *     but its value is available via {@link
> >> FetchConfiguration#getHint(String)}
> >> + *  3. Unrecognized: A key is neither supported nor recognized. The
> >> value of a
> >> + *     unrecognized key is neither recorded nor set anywhere.
> >> + *
> >> + *  If an incompatible value is supplied for a supported key, a
> >> non-fatal
> >> + *  {@link ArgumentException} is raised.
> >> + *
> >> + * @author Pinaki Poddar
> >> + *
> >> + * @since 2.0.0
> >> + *
> >> + * @nojavadoc
> >> + */
> >> +public class HintHandler {
> >> +    private final QueryImpl owner;
> >> +    private Map<String, Object> _hints;
> >> +    private Set<String> _supportedKeys;
> >> +    private Set<String> _supportedPrefixes;
> >> +
> >> +    static final String PREFIX_JPA = "javax.persistence.";
> >> +    static final String PREFIX_FETCHPLAN = "openjpa.FetchPlan.";
> >> +
> >> +    // These keys are directly handled in {@link QueryImpl} class.
> >> +    // Declaring a public static final String variable in this class
> >> will
> >> +    // make it register as a supported hint key
> >> +    // if you do not want that then annotate as {@link
> >> Reflectable(false)}.
> >> +    public static final String HINT_SUBCLASSES = "openjpa.Subclasses";
> >> +    public static final String HINT_FILTER_LISTENER =
> >> "openjpa.FilterListener";
> >> +    public static final String HINT_FILTER_LISTENERS =
> >> +        "openjpa.FilterListeners";
> >> +    public static final String HINT_AGGREGATE_LISTENER =
> >> +        "openjpa.AggregateListener";
> >> +    public static final String HINT_AGGREGATE_LISTENERS =
> >> +        "openjpa.AggregateListeners";
> >> +
> >> +    // JPA Specification 2.0 keys are mapped to equivalent FetchPlan
> >> keys
> >> +    public static Map<String,String> _jpaKeys = new TreeMap<String,
> >> String>();
> >> +    static {
> >> +        _jpaKeys.put(addPrefix(PREFIX_JPA, "query.timeout"),
> >> +            addPrefix(PREFIX_FETCHPLAN, "LockTimeout"));
> >> +    }
> >> +
> >> +    private static final String DOT = ".";
> >> +    private static final String BLANK = "";
> >> +    private static final Localizer _loc = Localizer.forPackage(
> >> +        HintHandler.class);
> >> +
> >> +    public HintHandler(QueryImpl impl) {
> >> +        owner = impl;
> >> +    }
> >> +
> >> +    /**
> >> +     * Gets all the recorded hint keys and their values.
> >> +     */
> >> +    @SuppressWarnings("unchecked")
> >> +    public Map<String, Object> getHints() {
> >> +        return _hints == null ? Collections.EMPTY_MAP
> >> +            : Collections.unmodifiableMap(_hints);
> >> +    }
> >> +
> >> +    /**
> >> +     * Record a key-value pair only only if the given key is supported.
> >> +     *
> >> +     * @return FALSE if the key is unrecognized.
> >> +     *         null (i.e. MAY BE) if the key is recognized, but not
> >> supported.
> >> +     *         TRUE if the key is supported.
> >> +     */
> >> +    public Boolean record(String hint, Object value) {
> >> +        if (hint == null)
> >> +            return Boolean.FALSE;
> >> +        if (isSupported(hint)) {
> >> +            if (_hints == null)
> >> +                _hints = new TreeMap<String, Object>();
> >> +            _hints.put(hint, value);
> >> +            return Boolean.TRUE;
> >> +        }
> >> +
> >> +        Log log = owner.getDelegate().getBroker().getConfiguration()
> >> +            .getLog(OpenJPAConfiguration.LOG_RUNTIME);
> >> +        String possible =
> >> StringDistance.getClosestLevenshteinDistance(hint,
> >> +            getSupportedHints());
> >> +        if (log.isWarnEnabled()) {
> >> +            log.warn(_loc.get("bad-query-hint", hint, possible));
> >> +        }
> >> +        return (isKnownHintPrefix(hint)) ? null : Boolean.FALSE;
> >> +    }
> >> +
> >> +    /**
> >> +     * Gets all the supported hint keys. The set of supported hint keys
> >> is
> >> +     * statically determined by collecting hint keys from the
> >> ProductDerivations
> >> +     * and reflecting upon some of the known classes.
> >> +     */
> >> +    public Set<String> getSupportedHints() {
> >> +        if (_supportedKeys == null) {
> >> +            _supportedKeys = new TreeSet<String>(new
> >> HintKeyComparator());
> >> +            _supportedPrefixes = new TreeSet<String>();
> >> +
> >> +            _supportedKeys.addAll(Reflection.getFieldValues(
> >> +                org.apache.openjpa.kernel.QueryHints.class,
> >> +                Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL,
> >> +                String.class));
> >> +
> >> +            _supportedKeys.addAll(addPrefix(PREFIX_FETCHPLAN,
> >> +                Reflection.getBeanStylePropertyNames(
> >> +                    owner.getFetchPlan().getClass())));
> >> +
> >> +            _supportedKeys.addAll(_jpaKeys.keySet());
> >> +
> >> +            _supportedKeys.addAll(Reflection.getFieldValues(
> >> +                HintHandler.class,
> >> +                Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL,
> >> +                String.class));
> >> +
> >> +
> >> _supportedKeys.addAll(ProductDerivations.getSupportedQueryHints());
> >> +
> >> +            for (String key : _supportedKeys) {
> >> +                _supportedPrefixes.add(getPrefixOf(key));
> >> +            }
> >> +        }
> >> +        return _supportedKeys;
> >> +    }
> >> +
> >> +    /**
> >> +     * Add a hint key to the set of supported hint keys.
> >> +     */
> >> +    public void addHintKey(String key) {
> >> +        getSupportedHints().add(key);
> >> +        _supportedPrefixes.add(getPrefixOf(key));
> >> +    }
> >> +
> >> +    public Set<String> getKnownPrefixes() {
> >> +        getSupportedHints();
> >> +        return _supportedPrefixes;
> >> +    }
> >> +
> >> +    /**
> >> +     * Affirms the given key matches one of the supported keys.
> >> +     */
> >> +    public boolean isSupported(String key) {
> >> +        return getSupportedHints().contains(key);
> >> +    }
> >> +
> >> +    /**
> >> +     * Affirms the given key has a prefix that matches with any of the
> >> +     * supported prefixes.
> >> +     */
> >> +    public boolean isSupportedPrefix(String key) {
> >> +        return getKnownPrefixes().contains(getPrefixOf(key));
> >> +    }
> >> +
> >> +    static Set<String> addPrefix(String prefix, Set<String> original) {
> >> +        Set<String> result = new TreeSet<String>();
> >> +        String join = prefix.endsWith(DOT) ? BLANK : DOT;
> >> +        for (String o : original)
> >> +            result.add(prefix + join + o);
> >> +        return result;
> >> +    }
> >> +
> >> +    static String addPrefix(String prefix, String original) {
> >> +        String join = prefix.endsWith(DOT) ? BLANK : DOT;
> >> +        return prefix + join + original;
> >> +    }
> >> +
> >> +    public static String removePrefix(String key, String prefix) {
> >> +        if (prefix == null)
> >> +            return key;
> >> +        if (!prefix.endsWith(DOT))
> >> +            prefix = prefix + DOT;
> >> +        if (key != null && key.startsWith(prefix))
> >> +            return key.substring(prefix.length());
> >> +        return key;
> >> +    }
> >> +
> >> +    static String getPrefixOf(String key) {
> >> +        int index = key == null ? -1 : key.indexOf(DOT);
> >> +        return (index != -1) ? key.substring(0,index) : key;
> >> +    }
> >> +
> >> +    boolean isKnownHintPrefix(String key) {
> >> +        String prefix = getPrefixOf(key);
> >> +        return getKnownPrefixes().contains(prefix);
> >> +    }
> >> +
> >> +    public static boolean hasPrefix(String key, String prefix) {
> >> +        if (key == null || prefix == null)
> >> +            return false;
> >> +        if (!prefix.endsWith(DOT))
> >> +            prefix = prefix + DOT;
> >> +        return key.startsWith(prefix);
> >> +    }
> >> +
> >> +    public void setHint(String key, Object value) {
> >> +        Boolean record = record(key, value);
> >> +        FetchConfiguration fetch =
> >> owner.getDelegate().getFetchConfiguration();
> >> +        ClassLoader loader =
> >> owner.getDelegate().getBroker().getClassLoader();
> >> +        if (record == Boolean.FALSE)
> >> +            return;
> >> +        if (record == null) {
> >> +            fetch.setHint(key, value);
> >> +            return;
> >> +        }
> >> +        try {
> >> +            if (HINT_SUBCLASSES.equals(key)) {
> >> +                if (value instanceof String)
> >> +                    value = Boolean.valueOf((String) value);
> >> +                owner.setSubclasses(((Boolean) value).booleanValue());
> >> +            } else if (HINT_FILTER_LISTENER.equals(key))
> >> +
> >> owner.addFilterListener(Filters.hintToFilterListener(value,
> >> +                    loader));
> >> +            else if (HINT_FILTER_LISTENERS.equals(key)) {
> >> +                FilterListener[] arr =
> >> Filters.hintToFilterListeners(value,
> >> +                    loader);
> >> +                for (int i = 0; i < arr.length; i++)
> >> +                    owner.addFilterListener(arr[i]);
> >> +            } else if (HINT_AGGREGATE_LISTENER.equals(key))
> >> +
> >> owner.addAggregateListener(Filters.hintToAggregateListener(
> >> +                    value, loader));
> >> +            else if (HINT_AGGREGATE_LISTENERS.equals(key)) {
> >> +                AggregateListener[] arr =
> >> Filters.hintToAggregateListeners(
> >> +                        value, loader);
> >> +                for (int i = 0; i < arr.length; i++)
> >> +                    owner.addAggregateListener(arr[i]);
> >> +            } else if (isFetchPlanHint(key)) {
> >> +                hintToSetter(owner.getFetchPlan(),
> >> +                    getFetchPlanProperty(key), value);
> >> +            } else if (HINT_RESULT_COUNT.equals(key)) {
> >> +                int v = (Integer)Filters.convert(value, Integer.class);
> >> +                if (v < 0)
> >> +                    throw new
> >> ArgumentException(_loc.get("bad-query-hint-value",
> >> +                        key, value), null,  null, false);
> >> +                    fetch.setHint(key, v);
> >> +            }  else if (HINT_INVALIDATE_PREPARED_QUERY.equals(key)) {
> >> +                fetch.setHint(key, Filters.convert(value,
> >> Boolean.class));
> >> +                owner.invalidatePreparedQuery();
> >> +            } else if (HINT_IGNORE_PREPARED_QUERY.equals(key)) {
> >> +                fetch.setHint(key, Filters.convert(value,
> >> Boolean.class));
> >> +                owner.ignorePreparedQuery();
> >> +            } else { // default
> >> +                fetch.setHint(key, value);
> >> +            }
> >> +            return;
> >> +        } catch (IllegalArgumentException iae) {
> >> +            throw new
> ArgumentException(_loc.get("bad-query-hint-value",
> >> +                key, value), null,  null, false);
> >> +        } catch (ClassCastException ce) {
> >> +            throw new
> ArgumentException(_loc.get("bad-query-hint-value",
> >> +                key, ce.getMessage()), null,  null, false);
> >> +        } catch (Exception e) {
> >> +            throw PersistenceExceptions.toPersistenceException(e);
> >> +        }
> >> +    }
> >> +
> >> +    private boolean isFetchPlanHint(String key) {
> >> +        return key.startsWith(PREFIX_FETCHPLAN)
> >> +           || (_jpaKeys.containsKey(key) &&
> >> isFetchPlanHint(_jpaKeys.get(key)));
> >> +    }
> >> +
> >> +    private String getFetchPlanProperty(String key) {
> >> +        if (key.startsWith(PREFIX_FETCHPLAN))
> >> +            return removePrefix(key, PREFIX_FETCHPLAN);
> >> +        else if (_jpaKeys.containsKey(key))
> >> +            return getFetchPlanProperty(_jpaKeys.get(key));
> >> +        else
> >> +            return key;
> >> +    }
> >> +
> >> +    private void hintToSetter(FetchPlan fetchPlan, String k, Object
> >> value) {
> >> +        if (fetchPlan == null || k == null)
> >> +            return;
> >> +
> >> +        Method setter = Reflection.findSetter(fetchPlan.getClass(), k,
> >> true);
> >> +        Class paramType = setter.getParameterTypes()[0];
> >> +        if (Enum.class.isAssignableFrom(paramType) && value instanceof
> >> String)
> >> +            value = Enum.valueOf(paramType, (String) value);
> >> +
> >> +        Filters.hintToSetter(fetchPlan, k, value);
> >> +    }
> >> +
> >> +    public static class HintKeyComparator implements Comparator<String>
> >> {
> >> +        public int compare(String s1, String s2) {
> >> +            if (getPrefixOf(s1).equals(getPrefixOf(s2))) {
> >> +                int n1 = countDots(s1);
> >> +                int n2 = countDots(s2);
> >> +                return (n1 == n2) ? s1.compareTo(s2) : (n1 - n2);
> >> +            } else
> >> +                return s1.compareTo(s2);
> >> +        }
> >> +
> >> +        public int countDots(String s) {
> >> +            if (s == null || s.length() == 0)
> >> +                return 0;
> >> +            int index = s.indexOf(DOT);
> >> +            return (index == -1) ? 0 : countDots(s.substring(index+1))
> +
> >> 1;
> >> +        }
> >> +    }
> >> +}
> >>
> >> Modified:
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java?rev=743396&r1=743395&r2=743396&view=diff
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
> >> (original)
> >> +++
> >>
> openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -18,8 +18,9 @@
> >>   */
> >>  package org.apache.openjpa.persistence;
> >>
> >> +import static
> >> org.apache.openjpa.kernel.QueryLanguages.LANG_PREPARED_SQL;
> >> +
> >>  import java.io.Serializable;
> >> -import java.lang.reflect.Method;
> >>  import java.sql.Time;
> >>  import java.sql.Timestamp;
> >>  import java.util.ArrayList;
> >> @@ -41,15 +42,12 @@
> >>  import javax.persistence.TemporalType;
> >>
> >>  import org.apache.openjpa.conf.OpenJPAConfiguration;
> >> -import org.apache.openjpa.enhance.Reflection;
> >>  import org.apache.openjpa.kernel.Broker;
> >>  import org.apache.openjpa.kernel.DelegatingQuery;
> >>  import org.apache.openjpa.kernel.DelegatingResultList;
> >>  import org.apache.openjpa.kernel.FetchConfiguration;
> >> -import org.apache.openjpa.kernel.Filters;
> >>  import org.apache.openjpa.kernel.PreparedQuery;
> >>  import org.apache.openjpa.kernel.PreparedQueryCache;
> >> -import org.apache.openjpa.kernel.QueryHints;
> >>  import org.apache.openjpa.kernel.QueryLanguages;
> >>  import org.apache.openjpa.kernel.QueryOperations;
> >>  import org.apache.openjpa.kernel.QueryStatistics;
> >> @@ -63,8 +61,6 @@
> >>  import org.apache.openjpa.util.RuntimeExceptionTranslator;
> >>  import org.apache.openjpa.util.UserException;
> >>
> >> -import static
> >> org.apache.openjpa.kernel.QueryLanguages.LANG_PREPARED_SQL;
> >> -
> >>  /**
> >>   * Implementation of {@link Query} interface.
> >>   *
> >> @@ -85,6 +81,8 @@
> >>      private Map<String, Object> _named;
> >>      private Map<Integer, Object> _positional;
> >>      private String _id;
> >> +
> >> +    private final HintHandler _hintHandler;
> >>
> >>      /**
> >>       * Constructor; supply factory exception translator and delegate.
> >> @@ -97,6 +95,7 @@
> >>                      org.apache.openjpa.kernel.Query query) {
> >>              _em = em;
> >>              _query = new DelegatingQuery(query, ret);
> >> +            _hintHandler = new HintHandler(this);
> >>      }
> >>
> >>      /**
> >> @@ -254,7 +253,7 @@
> >>      }
> >>
> >>      private Object execute() {
> >> -            if (_query.getOperation() != QueryOperations.OP_SELECT)
> >> +            if (!isNative() && _query.getOperation() !=
> QueryOperations.OP_SELECT)
> >>                      throw new
> InvalidStateException(_loc.get("not-select-query", _query
> >>                                      .getQueryString()), null, null,
> false);
> >>
> >> @@ -351,81 +350,8 @@
> >>
> >>      public OpenJPAQuery setHint(String key, Object value) {
> >>              _em.assertNotCloseInvoked();
> >> -            if (key == null)
> >> -                    return this;
> >> -            if (!key.startsWith("openjpa.")) {
> >> -                    _query.getFetchConfiguration().setHint(key, value);
> >> -                    return this;
> >> -            }
> >> -            String k = key.substring("openjpa.".length());
> >> -
> >> -            try {
> >> -                    if ("Subclasses".equals(k)) {
> >> -                            if (value instanceof String)
> >> -                                    value = Boolean.valueOf((String)
> value);
> >> -                            setSubclasses(((Boolean)
> value).booleanValue());
> >> -                    } else if ("FilterListener".equals(k))
> >> -
>  addFilterListener(Filters.hintToFilterListener(value, _query
> >> -
>  .getBroker().getClassLoader()));
> >> -                    else if ("FilterListeners".equals(k)) {
> >> -                            FilterListener[] arr =
> Filters.hintToFilterListeners(value,
> >> -
>  _query.getBroker().getClassLoader());
> >> -                            for (int i = 0; i < arr.length; i++)
> >> -                                    addFilterListener(arr[i]);
> >> -                    } else if ("AggregateListener".equals(k))
> >> -
>  addAggregateListener(Filters.hintToAggregateListener(value,
> >> -
>  _query.getBroker().getClassLoader()));
> >> -                    else if ("FilterListeners".equals(k)) {
> >> -                            AggregateListener[] arr =
> Filters.hintToAggregateListeners(
> >> -                                            value,
> _query.getBroker().getClassLoader());
> >> -                            for (int i = 0; i < arr.length; i++)
> >> -                                    addAggregateListener(arr[i]);
> >> -                    } else if (k.startsWith("FetchPlan.")) {
> >> -                            k = k.substring("FetchPlan.".length());
> >> -                            hintToSetter(getFetchPlan(), k, value);
> >> -                    } else if (k.startsWith("hint.")) {
> >> -                            if ("hint.OptimizeResultCount".equals(k)) {
> >> -                                    if (value instanceof String) {
> >> -                                            try {
> >> -                                                    value = new
> Integer((String) value);
> >> -                                            } catch
> (NumberFormatException nfe) {
> >> -                                            }
> >> -                                    }
> >> -                                    if (!(value instanceof Number)
> >> -                                                    || ((Number)
> value).intValue() < 0)
> >> -                                            throw new
> ArgumentException(_loc.get(
> >> -
>  "bad-query-hint-value", key, value), null,
> >> -                                                            null,
> false);
> >> -                    _query.getFetchConfiguration().setHint(key, value);
> >> -                            }  else if
> (QueryHints.HINT_INVALIDATE_PREPARED_QUERY.equals
> >> -                    (key)) {
> >> -                    _query.getFetchConfiguration().setHint(key,
> >> (Boolean)value);
> >> -                    invalidatePreparedQuery();
> >> -                } else if
> >> (QueryHints.HINT_IGNORE_PREPARED_QUERY.equals(key)) {
> >> -                    _query.getFetchConfiguration().setHint(key,
> >> (Boolean)value);
> >> -                    ignorePreparedQuery();
> >> -                } else {
> >> -                    _query.getFetchConfiguration().setHint(key, value);
> >> -                }
> >> -            } else
> >> -                            throw new
> ArgumentException(_loc.get("bad-query-hint", key),
> >> -                                            null, null, false);
> >> -                    return this;
> >> -            } catch (Exception e) {
> >> -                    throw
> PersistenceExceptions.toPersistenceException(e);
> >> -            }
> >> -    }
> >> -
> >> -    private void hintToSetter(FetchPlan fetchPlan, String k, Object
> value)
> >> {
> >> -            if (fetchPlan == null || k == null)
> >> -                    return;
> >> -
> >> -            Method setter = Reflection.findSetter(fetchPlan.getClass(),
> k, true);
> >> -            Class paramType = setter.getParameterTypes()[0];
> >> -            if (Enum.class.isAssignableFrom(paramType) && value
> instanceof String)
> >> -                    value = Enum.valueOf(paramType, (String) value);
> >> -
> >> -            Filters.hintToSetter(fetchPlan, k, value);
> >> +            _hintHandler.setHint(key, value);
> >> +            return this;
> >>      }
> >>
> >>      public OpenJPAQuery setParameter(int position, Calendar value,
> >> @@ -613,7 +539,7 @@
> >>       */
> >>      //TODO: JPA 2.0 Hints that are not set to FetchConfiguration
> >>      public Map<String, Object> getHints() {
> >> -        return _query.getFetchConfiguration().getHints();
> >> +        return _hintHandler.getHints();
> >>      }
> >>
> >>      public LockModeType getLockMode() {
> >> @@ -622,8 +548,7 @@
> >>      }
> >>
> >>      public Set<String> getSupportedHints() {
> >> -        throw new UnsupportedOperationException(
> >> -            "JPA 2.0 - Method not yet implemented");
> >> +        return _hintHandler.getSupportedHints();
> >>      }
> >>
> >>      public Query setLockMode(LockModeType lockMode) {
> >> @@ -704,7 +629,7 @@
> >>      /**
> >>       * Remove this query from PreparedQueryCache.
> >>       */
> >> -    private boolean invalidatePreparedQuery() {
> >> +    boolean invalidatePreparedQuery() {
> >>          PreparedQueryCache cache = _em.getPreparedQueryCache();
> >>          if (cache == null)
> >>              return false;
> >> @@ -716,7 +641,7 @@
> >>       * Ignores this query from PreparedQueryCache by recreating the
> >> original
> >>       * query if it has been cached.
> >>       */
> >> -    private void ignorePreparedQuery() {
> >> +    void ignorePreparedQuery() {
> >>          PreparedQuery cached = _em.getPreparedQuery(_id);
> >>          if (cached == null)
> >>              return;
> >>
> >> Modified:
> >>
> openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties?rev=743396&r1=743395&r2=743396&view=diff
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties
> >> (original)
> >> +++
> >>
> openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties
> >> Wed Feb 11 16:57:26 2009
> >> @@ -70,7 +70,7 @@
> >>  mult-results: Query returned multiple results: "{0}".
> >>  no-pos-named-params-mix: Cannot mix named and positional parameters in
> >> query \
> >>      "{0}".
> >> -bad-query-hint: "{0}" is not a recognized query hint.
> >> +bad-query-hint: "{0}" is not a supported query hint. May be you meant
> >> "{1}"?
> >>  bad-query-hint-value: Invalid value specified for query hint "{0}": {1}
> >>  detached: Cannot perform this operation on detached entity "{0}".
> >>  removed: Cannot perform this operation on removed entity "{0}".
> >>
> >> Modified:
> >>
> openjpa/trunk/openjpa-slice/src/main/java/org/apache/openjpa/slice/ProductDerivation.java
> >> URL:
> >>
> http://svn.apache.org/viewvc/openjpa/trunk/openjpa-slice/src/main/java/org/apache/openjpa/slice/ProductDerivation.java?rev=743396&r1=743395&r2=743396&view=diff
> >>
> ==============================================================================
> >> ---
> >>
> openjpa/trunk/openjpa-slice/src/main/java/org/apache/openjpa/slice/ProductDerivation.java
> >> (original)
> >> +++
> >>
> openjpa/trunk/openjpa-slice/src/main/java/org/apache/openjpa/slice/ProductDerivation.java
> >> Wed Feb 11 16:57:26 2009
> >> @@ -18,7 +18,9 @@
> >>   */
> >>  package org.apache.openjpa.slice;
> >>
> >> +import java.util.Collections;
> >>  import java.util.Map;
> >> +import java.util.Set;
> >>
> >>  import org.apache.openjpa.conf.OpenJPAProductDerivation;
> >>  import org.apache.openjpa.lib.conf.AbstractProductDerivation;
> >> @@ -98,4 +100,8 @@
> >>              log.warn(_loc.get("forced-set-config",
> >>                      prefix+"."+v.getProperty(), forced));
> >>      }
> >> +
> >> +    public Set<String> getSupportedQueryHints() {
> >> +        return Collections.singleton(HINT_TARGET);
> >> +    }
> >>  }
> >>
> >>
> >>
> >
> >
>
> --
> View this message in context:
> http://n2.nabble.com/Re%3A-svn-commit%3A-r743396---in--openjpa-trunk%3A-openjpa-jdbc-src-main-java-org-apache-openjpa-jdbc-conf--openjpa-kernel-src-main-java-org-apache-openjpa-enhance--openjpa-kernel-src-main-java-org-ap-tp2310190p2311099.html
> Sent from the OpenJPA Developers mailing list archive at Nabble.com.
>
>


-- 
Albert Lee.

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message