You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@openjpa.apache.org by Albert Lee <al...@gmail.com> on 2009/02/11 21:26:38 UTC

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

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 <pp...@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.

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

Posted by Donald Woods <dw...@apache.org>.
Yep, I'll address the missing getQueryTimeout() as part of OPENJPA-878.

Thanks for the info.

-Donald


Albert Lee wrote:
> When Don points out the use of
> 
>    assertEquals(5671, query.getFetchPlan().getQueryTimeout());
> 
> I assume the getQueryTimeout() method exists in the FetchPlan interface, but
> it is NOT. So you are correct that the getLockTimeout() is the only value
> that can be used for testing.
> 
> However the introduction of the following javax.persistence.* properties in
> OpenJPAConfiguration force us to address the same very issue:
> 
>         lockTimeout = addInt("LockTimeout");
>         lockTimeout.addEquivalentKey("javax.persistence.lock.timeout");
> 
>         queryTimeout = addInt("javax.persistence.query.timeout");
>         queryTimeout.setLoadKey("javax.persistence.query.timeout");
> 
> With this specification, one would expect 2 different values can be set
> independent of each other. The use of the lockTimeout field in
> FetchConfigurationImpl is not sufficient to support this behavior.
> 
> Albert Lee.
> 
> On Wed, Feb 11, 2009 at 2:45 PM, Pinaki Poddar <pp...@apache.org> wrote:
> 
>> Hi,
>>  Which interface/class defines getQueryTimeout() to test?
>>  In any case, please go ahead to change the test or (better) add a new one.
>>
>>
>> --
>> 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-a-tp2311149p2311244.html
>> Sent from the OpenJPA Developers mailing list archive at Nabble.com.
>>
>>
> 
> 

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

Posted by Pinaki Poddar <pp...@apache.org>.
Yes Albert now we are on the same page.



Albert Lee wrote:
> 
> When Don points out the use of
> 
>    assertEquals(5671, query.getFetchPlan().getQueryTimeout());
> 
> I assume the getQueryTimeout() method exists in the FetchPlan interface,
> but
> it is NOT. So you are correct that the getLockTimeout() is the only value
> that can be used for testing.
> 
> However the introduction of the following javax.persistence.* properties
> in
> OpenJPAConfiguration force us to address the same very issue:
> 
>         lockTimeout = addInt("LockTimeout");
>         lockTimeout.addEquivalentKey("javax.persistence.lock.timeout");
> 
>         queryTimeout = addInt("javax.persistence.query.timeout");
>         queryTimeout.setLoadKey("javax.persistence.query.timeout");
> 
> With this specification, one would expect 2 different values can be set
> independent of each other. The use of the lockTimeout field in
> FetchConfigurationImpl is not sufficient to support this behavior.
> 
> Albert Lee.
> 
> On Wed, Feb 11, 2009 at 2:45 PM, Pinaki Poddar <pp...@apache.org> wrote:
> 
>>
>> Hi,
>>  Which interface/class defines getQueryTimeout() to test?
>>  In any case, please go ahead to change the test or (better) add a new
>> one.
>>
>>
>> --
>> 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-a-tp2311149p2311244.html
>> Sent from the OpenJPA Developers mailing list archive at Nabble.com.
>>
>>
> 
> 
> -- 
> Albert Lee.
> 
> 

-- 
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-a-tp2311149p2312304.html
Sent from the OpenJPA Developers mailing list archive at Nabble.com.


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

Posted by Albert Lee <al...@gmail.com>.
When Don points out the use of

   assertEquals(5671, query.getFetchPlan().getQueryTimeout());

I assume the getQueryTimeout() method exists in the FetchPlan interface, but
it is NOT. So you are correct that the getLockTimeout() is the only value
that can be used for testing.

However the introduction of the following javax.persistence.* properties in
OpenJPAConfiguration force us to address the same very issue:

        lockTimeout = addInt("LockTimeout");
        lockTimeout.addEquivalentKey("javax.persistence.lock.timeout");

        queryTimeout = addInt("javax.persistence.query.timeout");
        queryTimeout.setLoadKey("javax.persistence.query.timeout");

With this specification, one would expect 2 different values can be set
independent of each other. The use of the lockTimeout field in
FetchConfigurationImpl is not sufficient to support this behavior.

Albert Lee.

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

>
> Hi,
>  Which interface/class defines getQueryTimeout() to test?
>  In any case, please go ahead to change the test or (better) add a new one.
>
>
> --
> 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-a-tp2311149p2311244.html
> Sent from the OpenJPA Developers mailing list archive at Nabble.com.
>
>


-- 
Albert Lee.

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

Posted by Pinaki Poddar <pp...@apache.org>.
Hi,
 Which interface/class defines getQueryTimeout() to test?
 In any case, please go ahead to change the test or (better) add a new one. 


-- 
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-a-tp2311149p2311244.html
Sent from the OpenJPA Developers mailing list archive at Nabble.com.