openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ppod...@apache.org
Subject svn commit: r899530 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/ openjpa-persistence-jdbc/src/main/j...
Date Fri, 15 Jan 2010 05:25:26 GMT
Author: ppoddar
Date: Fri Jan 15 05:25:25 2010
New Revision: 899530

URL: http://svn.apache.org/viewvc?rev=899530&view=rev
Log:
OPENJPA-900: Reduce reflection cost. Enumerate hint keys. 

Added:
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEnum.java   (with props)
Removed:
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractHintHandler.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationHintHandler.java
Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfiguration.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfigurationImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryHints.java
    openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
    openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/IsolationLevel.java
    openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCPersistenceProductDerivation.java
    openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/LRSSizeAlgorithm.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.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/FetchPlanImpl.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/kernel/JDBCFetchConfiguration.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfiguration.java?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfiguration.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfiguration.java Fri Jan 15 05:25:25 2010
@@ -119,7 +119,7 @@
      *
      * @since 0.4.0.0
      */
-    public Set getJoins();
+    public Set<String> getJoins();
 
     /**
      * Return true if the given fully-qualified join has been added.
@@ -144,7 +144,7 @@
      *
      * @since 0.4.0.0
      */
-    public JDBCFetchConfiguration addJoins(Collection fields);
+    public JDBCFetchConfiguration addJoins(Collection<String> fields);
 
     /**
      * Removes <code>field</code> to the set of fully-qualified field names to
@@ -160,7 +160,7 @@
      *
      * @since 0.4.0.0
      */
-    public JDBCFetchConfiguration removeJoins(Collection fields);
+    public JDBCFetchConfiguration removeJoins(Collection<String> fields);
 
     /**
      * Clears the set of field names to join when loading data.
@@ -215,7 +215,7 @@
      *
      * @since 1.0.3
      */
-    public Set getFetchInnerJoins();
+    public Set<String> getFetchInnerJoins();
 
     /**
      * Return true if the given fully-qualified inner fetch join has been added.
@@ -240,5 +240,5 @@
      *
      * @since 1.0.3
      */
-    public JDBCFetchConfiguration addFetchInnerJoins(Collection fields);
+    public JDBCFetchConfiguration addFetchInnerJoins(Collection<String> fields);
 }

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfigurationImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfigurationImpl.java?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfigurationImpl.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCFetchConfigurationImpl.java Fri Jan 15 05:25:25 2010
@@ -52,12 +52,32 @@
  * @author Abe White
  * @nojavadoc
  */
+@SuppressWarnings("serial")
 public class JDBCFetchConfigurationImpl
     extends FetchConfigurationImpl
     implements JDBCFetchConfiguration {
 
-    private static final Localizer _loc = Localizer.forPackage
-        (JDBCFetchConfigurationImpl.class);
+    private static final Localizer _loc = Localizer.forPackage(JDBCFetchConfigurationImpl.class);
+    
+    /**
+     * Hint keys that correspond to a mutable bean-style setter in this receiver.
+     * These keys are registered with both <code>openjpa.FetchPlan</code> and <code>openjpa.jdbc</code> as prefix.
+     * <br>
+     * A hint without a setter method is also recognized by this receiver.
+     */
+    static {
+        String[] prefixes = {"openjpa.FetchPlan", "openjpa.jdbc"};
+        Class<?> target = JDBCFetchConfiguration.class;
+        populateHintSetter(target, "EagerFetchMode", int.class, prefixes);
+        populateHintSetter(target, "FetchDirection", int.class, prefixes);
+        populateHintSetter(target, "Isolation", int.class, prefixes);
+        populateHintSetter(target, "setIsolation", "TransactionIsolation", int.class, "openjpa.jdbc");
+        populateHintSetter(target, "JoinSyntax", int.class, prefixes);
+        populateHintSetter(target, "SubclassFetchMode", int.class, prefixes);
+        populateHintSetter(target, "LRSSize", int.class, prefixes);
+        populateHintSetter(target, "setLRSSize", "LRSSizeAlgorithm", int.class, prefixes);
+        populateHintSetter(target, "ResultSetType", int.class, prefixes);
+    }
 
     /**
      * Configurable JDBC state shared throughout a traversal chain.
@@ -69,8 +89,8 @@
         public int direction = 0;
         public int size = 0;
         public int syntax = 0;
-        public Set joins = null;
-        public Set fetchInnerJoins = null;
+        public Set<String> joins = null;
+        public Set<String> fetchInnerJoins = null;
         public int isolationLevel = -1;
     }
 
@@ -138,7 +158,7 @@
             _state.eagerMode = mode;
         return this;
     }
-
+    
     public int getSubclassFetchMode() {
         return _state.subclassMode;
     }
@@ -254,7 +274,7 @@
         return this;
     }
 
-    public ResultList newResultList(ResultObjectProvider rop) {
+    public ResultList<?> newResultList(ResultObjectProvider rop) {
         // if built around a list, just use a simple wrapper
         if (rop instanceof ListResultObjectProvider)
             return new SimpleResultList(rop);
@@ -286,8 +306,10 @@
         return new SimpleResultList(rop);
     }
 
-    public Set getJoins() {
-        return (_state.joins == null) ? Collections.EMPTY_SET : _state.joins;
+    public Set<String> getJoins() {
+        if (_state.joins == null) 
+            return Collections.emptySet();
+        return _state.joins;
     }
 
     public boolean hasJoin(String field) {
@@ -301,7 +323,7 @@
         lock();
         try {
             if (_state.joins == null)
-                _state.joins = new HashSet();
+                _state.joins = new HashSet<String>();
             _state.joins.add(join);
         } finally {
             unlock();
@@ -309,11 +331,11 @@
         return this;
     }
 
-    public JDBCFetchConfiguration addJoins(Collection joins) {
+    public JDBCFetchConfiguration addJoins(Collection<String> joins) {
         if (joins == null || joins.isEmpty())
             return this;
-        for (Iterator itr = joins.iterator(); itr.hasNext();)
-            addJoin((String) itr.next());
+        for (Iterator<String> itr = joins.iterator(); itr.hasNext();)
+            addJoin(itr.next());
         return this;
     }
 
@@ -328,7 +350,7 @@
         return this;
     }
 
-    public JDBCFetchConfiguration removeJoins(Collection joins) {
+    public JDBCFetchConfiguration removeJoins(Collection<String> joins) {
         lock();
         try {
             if (_state.joins != null)
@@ -390,9 +412,10 @@
         return (JDBCConfiguration) conf;
     }
 
-    public Set getFetchInnerJoins() {
-        return (_state.fetchInnerJoins == null) ? Collections.EMPTY_SET
-            : _state.fetchInnerJoins;
+    public Set<String> getFetchInnerJoins() {
+        if (_state.fetchInnerJoins == null) 
+            return Collections.emptySet();
+        return _state.fetchInnerJoins;
     }
 
     public boolean hasFetchInnerJoin(String field) {
@@ -407,7 +430,7 @@
         lock();
         try {
             if (_state.fetchInnerJoins == null)
-                _state.fetchInnerJoins = new HashSet();
+                _state.fetchInnerJoins = new HashSet<String>();
             _state.fetchInnerJoins.add(join);
         } finally {
             unlock();
@@ -415,10 +438,10 @@
         return this;
     }
 
-    public JDBCFetchConfiguration addFetchInnerJoins(Collection joins) {
+    public JDBCFetchConfiguration addFetchInnerJoins(Collection<String> joins) {
         if (joins == null || joins.isEmpty())
             return this;
-        for (Iterator itr = joins.iterator(); itr.hasNext();)
+        for (Iterator<String> itr = joins.iterator(); itr.hasNext();)
             addFetchInnerJoin((String) itr.next());
         return this;
     }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java Fri Jan 15 05:25:25 2010
@@ -361,49 +361,58 @@
     public ResultList<?> newResultList(ResultObjectProvider rop);
 
     /**
-     * Sets an arbitrary query hint that may be utilized during
-     * execution. The hint may be datastore-specific.
+     * Sets an arbitrary query hint that may be utilized during execution. 
+     * The hint may be specific to a particular database. A hint, if known 
+     * to this receiver, may have a corresponding setter method, then the hint sets the value.
+     * Otherwise the hint is stored opaquely by the receiver.
      *
      * @param name the name of the hint
-     * @param value the value of the hint
-     * @since 0.4.0
+     * @param value the value of the hint. If the hint has a corresponding setter, then
+     * the type of value must be same as the setter argument. 
+     * @param original the value of the hint as specified by the user. 
+     * 
+     * @since 2.0.0
      */
-    public void setHint(String name, Object value);
-
+    public void setHint(String name, Object value, Object original);
+    
     /**
-     * Sets an arbitrary query hint that may be utilized during
-     * execution. The hint may be datastore-specific.
+     * Sets an arbitrary query hint that may be utilized during execution. 
+     * The hint may be specific to a particular database. A hint, if known 
+     * to this receiver, may have a corresponding setter method, then the hint sets the value.
+     * Otherwise the hint is stored opaquely by the receiver.
+     * <br>
+     * This is same as calling {@linkplain #setHint(String, Object, Object)} with the third
+     * argument being the same as the second.
      *
      * @param name the name of the hint
-     * @param value the value of the hint
+     * @param value the value of the hint. If the hint has a corresponding setter, then
+     * the type of value must be same as the setter argument. 
+     * 
      * @since 2.0.0
      */
-    public void setHint(String name, Object value, boolean validate);
+    public void setHint(String key, Object value);
 
     /**
-     * Returns the hint for the specific key, or null if the hint
-     * is not specified.
+     * Get the hint value for the specific key as originally set by the caller, or null if the hint is not specified.
      *
 	 * @param name the hint name
 	 * @since 0.4.0
 	 */
-	public Object getHint (String name);
+	public Object getHint (String key);
 	
-    /**
-     * Adds the hint and the associated value to the list.
-     *
-     * @param name the name of the hint
-     * @param value the value of the hint
-     * @since 2.0.0
-     */
-    public void addHint(String name, Object value);
-
 	/**
-     * Returns an immutable view of the currently active hints and their values.
+     * Get an immutable view of the currently active hints and their values.
+	 * The values are as specified by the user.
 	 * 
 	 * @since 2.0.0
 	 */
 	public Map<String, Object> getHints();
+	
+	/**
+	 * Affirm if the given hint has been set in this receiver.
+	 * 
+	 */
+	public boolean isHintSet(String key);
 
     /**
      * Root classes for recursive operations. This set is not thread safe.

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java Fri Jan 15 05:25:25 2010
@@ -19,6 +19,7 @@
 package org.apache.openjpa.kernel;
 
 import java.io.Serializable;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -29,7 +30,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.TreeMap;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.openjpa.conf.OpenJPAConfiguration;
@@ -62,8 +62,65 @@
 public class FetchConfigurationImpl
     implements FetchConfiguration, Cloneable {
 
-    private static final Localizer _loc = Localizer.forPackage
-        (FetchConfigurationImpl.class);
+    private static final Localizer _loc = Localizer.forPackage(FetchConfigurationImpl.class);
+    private static Map<String, Method> _hintSetters = new HashMap<String, Method>();
+    
+    /** 
+     * Registers hint keys that have a corresponding setter method.
+     * The hint keys are registered in <code>openjpa.FetchPlan</code> and <code>openjpa</code> as prefix.
+     * Also some keys are registered in <code>javax.persistence</code> namespace.
+     */
+    static {
+            String[] prefixes = {"openjpa.FetchPlan", "openjpa"};
+            Class<?> target = FetchConfiguration.class;
+            populateHintSetter(target, "ExtendedPathLookup", boolean.class, prefixes);
+            populateHintSetter(target, "FetchBatchSize", int.class, prefixes);
+            populateHintSetter(target, "FlushBeforeQueries", int.class, prefixes);
+            populateHintSetter(target, "LockScope", int.class, prefixes);
+            populateHintSetter(target, "LockTimeout", int.class, prefixes);
+            populateHintSetter(target, "setLockTimeout", "timeout", int.class, "javax.persistence.lock");
+            populateHintSetter(target, "MaxFetchDepth", int.class, prefixes);
+            populateHintSetter(target, "QueryTimeout", int.class, prefixes);
+            populateHintSetter(target, "setQueryTimeout", "timeout", int.class, "javax.persistence.query");
+            populateHintSetter(target, "ReadLockLevel", int.class, prefixes);
+            populateHintSetter(target, "setReadLockLevel", "ReadLockMode", int.class, prefixes);
+            populateHintSetter(target, "WriteLockLevel", int.class, prefixes);
+            populateHintSetter(target, "setWriteLockLevel", "WriteLockMode", int.class, prefixes);
+    }
+    
+    /**
+     * Populate static registry of hints.
+     *  
+     * @param target The name of the target class that will receive this hint. 
+     * @param hint the simple name of the hint without a prefix. 
+     * @param type the value argument type of the target setter method. 
+     * @param prefixes the prefixes will be added to the simple hint name. 
+     */
+    protected static void populateHintSetter(Class<?> target, String hint, Class<?> type, String...prefixes) {
+        populateHintSetter(target, "set" + hint, hint, type, prefixes);
+    }
+    
+    /**
+     * Populate static registry of hints.
+     *  
+     * @param target The name of the target class that will receive this hint. 
+     * @param method The name of the method in the target class that will receive this hint. 
+     * @param hint the simple name of the hint without a prefix. 
+     * @param type the value argument type of the target setter method. 
+     * @param prefixes the prefixes will be added to the simple hint name. 
+     */
+    protected static void populateHintSetter(Class<?> target, String method, String hint, Class<?> type, 
+            String...prefixes) {
+        try {
+            Method setter = target.getMethod(method, type);
+            for (String prefix : prefixes) {
+                _hintSetters.put(prefix + "." + hint, setter);
+            }
+        } catch (Exception e) {
+            // should not reach
+            throw new InternalException("setter for " + hint + " with argument " + type + " does not exist");
+        }
+    }
 
     /**
      * Configurable state shared throughout a traversal chain.
@@ -90,7 +147,7 @@
         public boolean fetchGroupContainsAll = false;
         public boolean extendedPathLookup = false;
         public DataCacheRetrieveMode cacheRetrieveMode;
-        public DataCacheStoreMode cacheStoreMode;
+        public DataCacheStoreMode cacheStoreMode;        
     }
 
     private final ConfigurationState _state;
@@ -101,7 +158,6 @@
     private boolean _load = true;
     private int _availableRecursion;
     private int _availableDepth;
-    private FetchConfigurationHintHandler _hintHandler;
 
     public FetchConfigurationImpl() {
         this(null);
@@ -110,7 +166,6 @@
     protected FetchConfigurationImpl(ConfigurationState state) {
         _state = (state == null) ? new ConfigurationState() : state;
         _availableDepth = _state.maxFetchDepth;
-        _hintHandler = new FetchConfigurationHintHandler(this);
     } 
 
     public StoreContext getContext() {
@@ -501,16 +556,6 @@
     }
 
     public int getReadLockLevel() {
-        String lockModeKey = "openjpa.FetchPlan.ReadLockMode";
-        String deferLockModeKey = lockModeKey + ".Defer";
-        Integer value = (Integer)getHint(deferLockModeKey);
-        if (value != null) {
-            if (isActiveTransaction()) {
-                removeHint(deferLockModeKey);
-                setReadLockLevel(value);
-            } else
-                return value;
-        }
         return _state.readLockLevel;
     }
 
@@ -546,16 +591,6 @@
     }
 
     public int getWriteLockLevel() {
-        String lockModeKey = "openjpa.FetchPlan.WriteLockMode";
-        String deferLockModeKey = lockModeKey + ".Defer";
-        Integer value = (Integer)getHint(deferLockModeKey);
-        if (value != null) {
-            if (isActiveTransaction()) {
-                removeHint(deferLockModeKey);
-                setWriteLockLevel(value);
-            } else
-                return value;
-        }
         return _state.writeLockLevel;
     }
 
@@ -610,17 +645,93 @@
     private boolean isActiveTransaction() {
         return (_state.ctx != null && _state.ctx.isActive());
     }
-
-    public void setHint(String name, Object value) {
-        setHint(name, value, false);
+    
+    /**
+     * Gets the current hints set on this receiver. 
+     * The values designate the actual value specified by the caller and not the values
+     * that may have been actually set on the state variables of this receiver.
+     * 
+     */
+    public Map<String,Object> getHints() {
+        if (_state.hints == null)
+            return Collections.emptyMap();
+        return Collections.unmodifiableMap(_state.hints);
     }
-
-    public void setHint(String name, Object value, boolean validThrowException) {
-        if (_hintHandler.setHint(name, value, validThrowException))
-            addHint(name, value);
+    
+    /**
+     * Affirms if the given key is set as a hint.
+     */
+    public boolean isHintSet(String key) {
+        return _state.hints != null && _state.hints.containsKey(key);
     }
-
-    public void addHint(String name, Object value) {
+    
+    /**
+     * Removes the given keys and their hint value.
+     */
+    public void removeHint(String...keys) {
+        if (keys == null || _state.hints == null )
+            return;
+        for (String key : keys) {
+            _state.hints.remove(key);
+        }
+    }
+    
+    public Collection<String> getSupportedHints() {
+        return _hintSetters.keySet();
+    }
+    
+    /**
+     * Same as <code>setHint(key, value, value)</code>.
+     * 
+     * @see #setHint(String, Object, Object)
+     */
+    public void setHint(String key, Object value) {
+        setHint(key, value, value);
+    }
+    
+    /**
+     * Sets the hint to the given value.
+     * If the key corresponds to a known key, then that value is set via the setter method.
+     * Otherwise it is put into opaque hints map.  
+     * <br>
+     * In either case, the original value is put in the hints map.
+     * So essential difference between setting a value directly by a setter and via a hint is the memory
+     * of this original value.
+     * <br>
+     * The other important difference is setting lock levels. Setting of lock level via setter method needs
+     * active transaction. But setting via hint does not. 
+     * @param key a hint key. If it is one of the statically registered hint key then the setter is called.
+     * @param value to be set. The given value type must match the argument type of the setter, if one exists.
+     * @param original value as specified by the caller. This value is put in the hints map.
+     * 
+     * @exception IllegalArgumentException if the given value is not acceptable by the setter method, if one
+     * exists corresponds the given hint key.
+     */
+    public void setHint(String key, Object value, Object original) {
+        if (key == null)
+            return;
+        if (_hintSetters.containsKey(key)) {
+            Method setter = _hintSetters.get(key);
+            String methodName = setter.getName();
+            try {
+                if ("setReadLockLevel".equals(methodName) && !isActiveTransaction()) {
+                    _state.readLockLevel = (Integer)value;
+                } else if ("setWriteLockLevel".equals(methodName) && !isActiveTransaction()) {
+                    _state.writeLockLevel = (Integer)value;
+                } else {
+                    setter.invoke(this, value);
+                }
+            } catch (Exception e) {
+                if (e instanceof IllegalArgumentException)
+                    throw (IllegalArgumentException)e;
+                throw new IllegalArgumentException(_loc.get("bad-hint-value", key, toString(value), 
+                        toString(original)).getMessage(), e);
+            }
+        }
+        addHint(key, original);
+    }
+    
+    private void addHint(String name, Object value) {
         lock();
         try {
             if (_state.hints == null)
@@ -639,16 +750,6 @@
         return (_state.hints == null) ? null : _state.hints.remove(name);
     }
     
-    public Map<String, Object> getHints() {
-        if (_state.hints == null)
-            return Collections.emptyMap();
-        Map<String, Object> result = new TreeMap<String, Object>();
-        for (Object key : _state.hints.keySet()) {
-            result.put(key.toString(), _state.hints.get(key));
-        }
-        return result;
-    }
-
     public Set<Class<?>> getRootClasses() {
         if (_state.rootClasses == null) return Collections.emptySet(); 
         return _state.rootClasses;
@@ -926,4 +1027,7 @@
         return buf.toString();
     }
 
+    protected String toString(Object o) {
+        return o == null ? "null" : o.toString() + "[" + o.getClass().getName() + "]";
+    }
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryHints.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryHints.java?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryHints.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryHints.java Fri Jan 15 05:25:25 2010
@@ -22,12 +22,20 @@
  * Standard query hint keys.
  */
 public interface QueryHints {
+    // 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";
     
     /** 
      * Hint to specify the number of rows to optimize for.
      */
-    public static final String HINT_RESULT_COUNT =
-        "openjpa.hint.OptimizeResultCount";
+    public static final String HINT_RESULT_COUNT = "openjpa.hint.OptimizeResultCount";
     
     /**
      * Hints to signal that the JPQL/SQL query string contains a parameter

Modified: openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties (original)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties Fri Jan 15 05:25:25 2010
@@ -412,7 +412,7 @@
 	for correctness. See nested exception for details.
 invalid-timeout: An invalid timeout of {0} milliseconds was ignored.  \
     Expected a value that is greater than or equal to -1.
-bad-hint-value: "{1}" is not a valid value for hint "{0}" caused by: {2}.
+bad-hint-value: Hint "{0}" can not be set to {1}. The original value was {2}. See nested exception for details.
 bad-flush-before-queries: Invalid flush before queries type. Valid values are \
 	"true"(0), "false"(1) or "with-connection"(2). Specified value: {0}.
 bad-lock-level: Invalid lock mode/level. Valid values are \

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/IsolationLevel.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/IsolationLevel.java?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/IsolationLevel.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/IsolationLevel.java Fri Jan 15 05:25:25 2010
@@ -21,6 +21,7 @@
 import java.sql.Connection;
 
 import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
+import org.apache.openjpa.persistence.OpenJPAEnum;
 
 /**
  * Isolation levels for use in {@link JDBCFetchPlan#setIsolation}.
@@ -28,18 +29,20 @@
  * @since 0.9.7
  * @published
  */
-public enum IsolationLevel {
-    DEFAULT(-1),
-    NONE(Connection.TRANSACTION_NONE),
-    READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
-    READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),
-    REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
-    SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);
+public enum IsolationLevel implements OpenJPAEnum<IsolationLevel>{
+    DEFAULT(-1, "default"),
+    NONE(Connection.TRANSACTION_NONE, "none"),
+    READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED, "read-uncommitted", "READ_UNCOMMITTED"),
+    READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED, "read-committed", "READ_COMMITTED"),
+    REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ, "repeatable-read", "REPEATABLE_READ"),
+    SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE, "serializable");
 
     private final int _connectionConstant;
+    private final String[] _names;
 
-    private IsolationLevel(int connectionConstant) {
+    private IsolationLevel(int connectionConstant, String... names) {
         _connectionConstant = connectionConstant;
+        _names = names;
     }
 
     public int getConnectionConstant() {
@@ -72,4 +75,31 @@
                     Integer.valueOf(constant).toString());
         }
     }
+
+    public IsolationLevel fromKernelConstant(int i) {
+        return IsolationLevel.fromConnectionConstant(i);
+    }
+
+    public int toKernelConstant() {
+        return getConnectionConstant();
+    }
+    
+    public static int toKernelConstantFromString(String s) {
+        for (IsolationLevel level : IsolationLevel.values()) {
+            for (String name : level._names) {
+                if (name.equalsIgnoreCase(s) || String.valueOf(level.toKernelConstant()).equals(s))
+                    return level.toKernelConstant();
+            }
+        }
+        throw new IllegalArgumentException(s + " is not a valid name for " + IsolationLevel.class.getName());
+    }
+    
+    public int convertToKernelConstant(String s) {
+        return IsolationLevel.toKernelConstantFromString(s);
+    }
+    
+    public int convertToKernelConstant(int i) {
+        return IsolationLevel.fromConnectionConstant(i).toKernelConstant();
+    }
+
 }

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCPersistenceProductDerivation.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCPersistenceProductDerivation.java?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCPersistenceProductDerivation.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/JDBCPersistenceProductDerivation.java Fri Jan 15 05:25:25 2010
@@ -19,13 +19,18 @@
 package org.apache.openjpa.persistence.jdbc;
 
 import java.security.AccessController;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.openjpa.conf.OpenJPAConfiguration;
 import org.apache.openjpa.conf.OpenJPAProductDerivation;
 import org.apache.openjpa.conf.Specification;
 import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
 import org.apache.openjpa.jdbc.kernel.JDBCStoreManager;
+import org.apache.openjpa.jdbc.sql.MySQLDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
 import org.apache.openjpa.lib.conf.AbstractProductDerivation;
 import org.apache.openjpa.lib.conf.Configuration;
 import org.apache.openjpa.lib.util.J2DoPrivHelper;
@@ -42,6 +47,7 @@
     extends AbstractProductDerivation 
     implements OpenJPAProductDerivation {
     
+    
     public void putBrokerFactoryAliases(Map m) {
     }
 
@@ -100,5 +106,31 @@
         conf.mappingDefaultsPlugin.setDefault(jpa.getName());
         conf.mappingDefaultsPlugin.setString(jpa.getName());
         return true;
+    } 
+    
+    /**
+     * Hint keys correspond to some (not all) bean-style mutable property name in JDBCFetchConfiguration.
+     * The fully qualified key is prefixed with <code>openjpa.jdbc</code>.
+     */
+    private static Set<String> _hints = new HashSet<String>();
+    static {
+        _hints.add("openjpa.FetchPlan.EagerFetchMode");
+        _hints.add("openjpa.FetchPlan.FetchDirection");
+        _hints.add("openjpa.FetchPlan.TransactionIsolation");
+        _hints.add("openjpa.FetchPlan.JoinSyntax");
+        _hints.add("openjpa.FetchPlan.LRSSize");
+        _hints.add("openjpa.FetchPlan.ResultSetType");
+        _hints.add("openjpa.FetchPlan.SubclassFetchMode");
+        
+        _hints.add(MySQLDictionary.SELECT_HINT);
+        _hints.add(OracleDictionary.SELECT_HINT);
+        
+        _hints = Collections.unmodifiableSet(_hints);
     }
+
+    @Override
+    public Set<String> getSupportedQueryHints() {
+        return _hints;
+    }
+
 }

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/LRSSizeAlgorithm.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/LRSSizeAlgorithm.java?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/LRSSizeAlgorithm.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/LRSSizeAlgorithm.java Fri Jan 15 05:25:25 2010
@@ -19,6 +19,8 @@
 package org.apache.openjpa.persistence.jdbc;
 
 import org.apache.openjpa.jdbc.kernel.LRSSizes;
+import org.apache.openjpa.kernel.FetchConfiguration;
+import org.apache.openjpa.persistence.OpenJPAEnum;
 
 /**
  * Algorithm to use for computing the size of an LRS relation.
@@ -26,18 +28,20 @@
  * @since 1.0.0
  * @published
  */
-public enum LRSSizeAlgorithm {
-    UNKNOWN(LRSSizes.SIZE_UNKNOWN),
-    LAST(LRSSizes.SIZE_LAST),
-    QUERY(LRSSizes.SIZE_QUERY);
+public enum LRSSizeAlgorithm implements OpenJPAEnum<Enum<?>> {
+    UNKNOWN(LRSSizes.SIZE_UNKNOWN, "unknown"),
+    LAST(LRSSizes.SIZE_LAST, "last"),
+    QUERY(LRSSizes.SIZE_QUERY, "query");
 
     private final int lrsConstant;
-
-    private LRSSizeAlgorithm(int value) {
+    private final String[] _names;
+    
+    private LRSSizeAlgorithm(int value, String...aliases) {
         lrsConstant = value;
+        _names = aliases;
     }
 
-    int toKernelConstant() {
+    public int toKernelConstant() {
         return lrsConstant;
     }
 
@@ -56,4 +60,30 @@
                 throw new IllegalArgumentException(kernelConstant + "");
         }
     }
+
+    public int convertToKernelConstant(String s) {
+        return LRSSizeAlgorithm.toKernelConstantFromString(s);
+    }
+    
+    public int convertToKernelConstant(int i) {
+        try {
+            if (i == FetchConfiguration.DEFAULT)
+                return i;
+            return LRSSizeAlgorithm.values()[i].ordinal();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw new IllegalArgumentException(i + " is invalid value for LRSSize Algorithm");
+        }
+    }
+    
+    public static int toKernelConstantFromString(String s) {
+        for (LRSSizeAlgorithm level : LRSSizeAlgorithm.values()) {
+            for (String name : level._names) {
+                if (name.equalsIgnoreCase(s) || String.valueOf(level.toKernelConstant()).equals(s))
+                    return level.toKernelConstant();
+            }
+        }
+        throw new IllegalArgumentException(s + " is not a valid name for " + IsolationLevel.class.getName());
+    }
+
+
 }

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryTimeout.java Fri Jan 15 05:25:25 2010
@@ -799,8 +799,7 @@
         } catch (Exception e) {
             // expected - setHint(-2000) should cause IllegalArgumentException
             checkException("testQueryTimeout5()", e, 
-                IllegalArgumentException.class, "invalid timeout of "
-                + NumberFormat.getIntegerInstance().format(setTime));
+                IllegalArgumentException.class, null);
         } finally {
             if ((em != null) && em.isOpen()) {
                 em.close();

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=899530&r1=899529&r2=899530&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 Fri Jan 15 05:25:25 2010
@@ -94,7 +94,6 @@
      *
      * @since 1.0.0
      */
-    @Reflectable(false)
     public boolean getQueryResultCacheEnabled();
 
     /**
@@ -109,7 +108,6 @@
     /**
      * @deprecated use {@link #getQueryResultCacheEnabled()} instead.
      */
-    @Reflectable(false)
     public boolean getQueryResultCache();
 
     /**
@@ -117,51 +115,8 @@
      */
     public FetchPlan setQueryResultCache(boolean cache);
     
-    /**
-     * Gets the hint for the given key.
-     * 
-     * @since 2.0.0
-     */
-    public Object getHint(String key);
-    
-    /**
-     * Sets the hint for the given key to the given value.
-     * 
-     * @since 2.0.0
-     */
-    public void setHint(String key, Object value);
     
     /**
-     * Sets the hint for the given key to the given value.
-     * 
-     * @since 2.0.0
-     */
-    public void setHint(String key, Object value, boolean validThrowException);
-
-    /**
-     * Adds the hint and the associated value to the list.
-     *
-     * @param name the name of the hint
-     * @param value the value of the hint
-     * @since 2.0.0
-     */
-    public void addHint(String name, Object value);
-
-    /**
-     * Sets the hint keys and values currently set of this receiver.
-     * 
-     * @since 2.0.0
-     */
-    public void addHints(Map<String, Object> hints);
-
-    /**
-     * Gets the hint keys and values currently set of this receiver.
-     * 
-     * @since 2.0.0
-     */
-    public Map<String, Object> getHints();
-
-    /**
      * Returns the names of the fetch groups that this component will use
      * when loading objects. Defaults to the
      * <code>openjpa.FetchGroups</code> setting.
@@ -411,4 +366,28 @@
      * @since 2.0.0
      */
     public FetchPlan setCacheRetrieveMode(DataCacheRetrieveMode mode);
+    
+    /**
+     * Set the hint for the given key to the given value.
+     * 
+     * @param value the value of the hint.
+     * @param name the name of the hint.
+     * 
+     * @since 2.0.0
+     */
+    public void setHint(String key, Object value);
+
+    /**
+     * Get the hints and their values currently set on this receiver.
+     * 
+     * @return empty map if no hint has been set.
+     */
+    Map<String, Object> getHints();
+    
+    /**
+     * Get the hint value for the given key.
+     * 
+     * @return null if the key has not been set.
+     */
+    Object getHint(String key);
 }

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java?rev=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java Fri Jan 15 05:25:25 2010
@@ -21,7 +21,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import javax.persistence.LockModeType;
@@ -31,6 +33,7 @@
 import org.apache.openjpa.kernel.DataCacheStoreMode;
 import org.apache.openjpa.kernel.DelegatingFetchConfiguration;
 import org.apache.openjpa.kernel.FetchConfiguration;
+import org.apache.openjpa.kernel.QueryFlushModes;
 
 /**
  * Implements FetchPlan via delegation to FetchConfiguration.
@@ -44,23 +47,82 @@
 	implements FetchPlan {
 
     private final DelegatingFetchConfiguration _fetch;
-    private FetchPlanHintHandler _hintHandler;
+    
+    /**
+     * Structure holds ranking of equivalent hint keys. Each entry value is a list of other keys that are higher rank
+     * than the entry key.   
+     */
+    protected static Map<String, List<String>> _precedence = new HashMap<String, List<String>>();
+    
+    /**
+     * Structure holds one or more converters for a user-specified hint value. 
+     */
+    protected static Map<String,HintValueConverter[]> _hints = new HashMap<String,HintValueConverter[]>();
+    
+    /**
+     * Statically registers supported hint keys with their ranking and converters. 
+     */
+    static {
+        registerHint(new String[]{"openjpa.FetchPlan.ExtendedPathLookup"}, 
+                new HintValueConverter.StringToBoolean());
+        registerHint(new String[]{"openjpa.FetchBatchSize", "openjpa.FetchPlan.FetchBatchSize"}, 
+                new HintValueConverter.StringToInteger());
+        registerHint(new String[]{"openjpa.MaxFetchDepth", "openjpa.FetchPlan.MaxFetchDepth"}, 
+                new HintValueConverter.StringToInteger());
+        registerHint(new String[]{"openjpa.LockTimeout", "openjpa.FetchPlan.LockTimeout", 
+                "javax.persistence.lock.timeout"}, new HintValueConverter.StringToInteger());
+        registerHint(new String[]{"openjpa.QueryTimeout", "openjpa.FetchPlan.QueryTimeout", 
+                "javax.persistence.query.timeout"}, new HintValueConverter.StringToInteger());
+        registerHint(new String[]{"openjpa.FlushBeforeQueries", "openjpa.FetchPlan.FlushBeforeQueries"}, 
+                new HintValueConverter.StringToInteger(
+                   new String[] {"0", "1", "2"},
+                   new int[]{QueryFlushModes.FLUSH_TRUE, QueryFlushModes.FLUSH_FALSE, 
+                           QueryFlushModes.FLUSH_WITH_CONNECTION}));
+        registerHint(new String[]{"openjpa.ReadLockMode", "openjpa.FetchPlan.ReadLockMode"},
+                new MixedLockLevelsHelper());
+        registerHint(new String[]{"openjpa.ReadLockLevel", "openjpa.FetchPlan.ReadLockLevel"},
+                new MixedLockLevelsHelper());
+        registerHint(new String[]{"openjpa.WriteLockMode", "openjpa.FetchPlan.WriteLockMode"}, 
+                new MixedLockLevelsHelper());
+        registerHint(new String[]{"openjpa.WriteLockLevel", "openjpa.FetchPlan.WriteLockLevel"}, 
+                new MixedLockLevelsHelper());
+    }
+    
+    /**
+     * Registers a hint key with its value converters. 
+     * 
+     * @param keys a set of keys in increasing order of ranking. Can not be null or empty.
+     * 
+     * @param converters array of converters that are attempts in order to convert a user-specified hint value
+     * to a value that is consumable by the kernel.
+     */
+    protected static void registerHint(String[] keys, HintValueConverter... converters) {
+        for (String key : keys) {
+            _hints.put(key, converters);
+        }
+        if (keys.length > 1) {
+            for (int i = 0; i < keys.length-1; i++) {
+                List<String> list = new ArrayList<String>(keys.length-i-1);
+                for (int j = i+1; j < keys.length; j++) {
+                    list.add(keys[j]);
+                }
+                _precedence.put(keys[i], list);
+            }
+        }
+    }
     
     /**
      * Constructor; supply delegate.
      */
     public FetchPlanImpl(FetchConfiguration fetch) {
         _fetch = newDelegatingFetchConfiguration(fetch);
-        _hintHandler = new FetchPlanHintHandler(this);
     }
 
     /**
      * Create a new exception-translating delegating fetch configuration.
      */
-    protected DelegatingFetchConfiguration newDelegatingFetchConfiguration
-        (FetchConfiguration fetch) {
-        return new DelegatingFetchConfiguration(fetch,
-            PersistenceExceptions.TRANSLATOR);
+    protected DelegatingFetchConfiguration newDelegatingFetchConfiguration(FetchConfiguration fetch) {
+        return new DelegatingFetchConfiguration(fetch, PersistenceExceptions.TRANSLATOR);
     }
 
     /**
@@ -287,23 +349,30 @@
         return _fetch.getHint(key);
     }
     
-    public void addHint(String key, Object value) {
-        _fetch.addHint(key, value);
-    }
-
+    /**
+     * Sets the hint after converting the value appropriately.
+     * If a higher ranking equivalent hint is already set, then bypasses this hint. 
+     */
     public void setHint(String key, Object value) {
-        setHint(key, value, true);
-    }
-
-    public void setHint(String key, Object value, boolean validThrowException) {
-        if( _hintHandler.setHint(key, value, validThrowException) )
-            _fetch.addHint(key, value);
+        if (!isRecognizedHint(key))
+            return;
+        if (_precedence.containsKey(key)) {
+            List<String> higherKeys = _precedence.get(key);
+            for (String higherKey : higherKeys) {
+                if (_fetch.isHintSet(higherKey))
+                    return;
+            }
+        }
+        Object newValue = convertHintValue(key, value); 
+        _fetch.setHint(key, newValue, value);
     }
 
-    public void addHints(Map<String, Object> hints) {
-        if (hints != null && hints.size() > 0) {
-            for (String name : hints.keySet())
-                setHint(name, hints.get(name), false);
+    public void setHints(Map<String, Object> hints) {
+        if (hints == null || hints.isEmpty()) {
+            return;
+        }
+        for (Map.Entry<String,Object> hint : hints.entrySet()) {
+            setHint(hint.getKey(), hint.getValue());
         }
     }
     
@@ -340,4 +409,36 @@
         _fetch.setCacheRetrieveMode(mode);
         return this;
     }
+
+    Object convertHintValue(String key, Object value) {
+        if (value == null)
+            return null;
+        HintValueConverter[] converters = _hints.get(key);
+        if (converters == null)
+            return value;
+        for (HintValueConverter converter : converters) {
+            if (converter.canConvert(value.getClass())) {
+                return converter.convert(value);
+            }
+        }
+        return value;
+    }
+    
+    boolean isRecognizedHint(String key) {
+        if (key == null)
+            return false;
+        if (_hints.containsKey(key))
+            return true;
+        return key.startsWith("openjpa.");
+    }
+    
+    boolean intersects(Collection<String> keys, Collection<String> b) {
+        if (keys == null || keys.isEmpty() || b == null || b.isEmpty())
+            return false;
+        for (String key : keys) {
+            if (b.contains(key))
+                return true;
+        }
+        return false;
+    }
 }

Modified: 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=899530&r1=899529&r2=899530&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/HintHandler.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/HintHandler.java Fri Jan 15 05:25:25 2010
@@ -18,23 +18,18 @@
  */
 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.Modifier;
 import java.util.Collections;
-import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
 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.QueryHints;
 import org.apache.openjpa.kernel.exps.AggregateListener;
 import org.apache.openjpa.kernel.exps.FilterListener;
 import org.apache.openjpa.lib.conf.ProductDerivation;
@@ -97,206 +92,172 @@
  * 
  * @nojavadoc
  */
-public class HintHandler extends FetchPlanHintHandler {
+public class HintHandler  {
+  protected final QueryImpl<?> owner;
 
-    private static final Localizer _loc = Localizer.forPackage(
-        HintHandler.class);
+    private static final Localizer _loc = Localizer.forPackage(HintHandler.class);
+    protected static Set<String> _supportedHints = ProductDerivations.getSupportedQueryHints();
 
-    private final QueryImpl owner;
+    protected static final String PREFIX_OPENJPA = "openjpa.";
+    protected static final String PREFIX_JDBC = PREFIX_OPENJPA + "jdbc.";
+    protected static final String PREFIX_FETCHPLAN = PREFIX_OPENJPA + "FetchPlan.";
     private Map<String, Object> _hints;
-    private static Set<String> _supportedKeys;
-    private static Set<String> _supportedPrefixes;
-    
-    // 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";
+
     
-    HintHandler(QueryImpl impl) {
-        super((FetchPlanImpl)impl.getFetchPlan());
+    HintHandler(QueryImpl<?> impl) {
+        super();
         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.
      */
-    private Boolean record(String hint, Object value) {
+    protected Boolean record(String hint, Object value) {
         if (hint == null)
             return Boolean.FALSE;
-        if (isSupported(hint)) {
+        if (_supportedHints.contains(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>();
-            _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(javaxHintsMap.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));
-            }
+        if (isKnownPrefix(hint)) {
+            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 null; // possible but not registered
         }
-        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.
-     */
-    private boolean isSupported(String key) {
-        return getSupportedHints().contains(key);
-    }
-    
-    private boolean isKnownHintPrefix(String key) {
-        String prefix = getPrefixOf(key);
-        return getKnownPrefixes().contains(prefix);
+        return Boolean.FALSE; // not possible
     }
 
     public void setHint(String key, Object value) {
-        owner.lock();
-        try {
-            Boolean record = record(key, value);
-            if (record == Boolean.FALSE)
-                return;
-            FetchPlan plan = owner.getFetchPlan();
-            if (record == null) {
-                plan.setHint(key, value);
-                return;
-            }
-            // request to throw IllegalArgumentException, if needed.
-            if (setHint(key, value, true))
-                plan.addHint(key, value);
-        } finally {
-            owner.unlock();
+        Boolean status = record(key, value);
+        if (Boolean.FALSE.equals(status))
+            return;
+        FetchPlan plan = owner.getFetchPlan();
+        if (status == null) {
+            plan.setHint(key, value);
+            return;
         }
-    }
-    
-    protected boolean setHintInternal(String key, Object value,
-        boolean validateThrowException) {
+        
         ClassLoader loader = owner.getDelegate().getBroker().getClassLoader();
-        FetchPlan fPlan = owner.getFetchPlan();
-        boolean objectSet = true;
-        if (HINT_SUBCLASSES.equals(key)) {
+        if (QueryHints.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)) {
+        } else if (QueryHints.HINT_FILTER_LISTENER.equals(key)) {
+            owner.addFilterListener(Filters.hintToFilterListener(value, loader));
+        } else if (QueryHints.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++)
+        } else if (QueryHints.HINT_AGGREGATE_LISTENER.equals(key)) {
+            owner.addAggregateListener(Filters.hintToAggregateListener(value, loader));
+        } else if (QueryHints.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 (HINT_RESULT_COUNT.equals(key)) {
+            }
+        } else if (QueryHints.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);
-            fPlan.setHint(key, v);
-            objectSet = false;
-        } else if (HINT_INVALIDATE_PREPARED_QUERY.equals(key)) {
-            fPlan.setHint(key, Filters.convert(value, Boolean.class));
+            if (v < 0) {
+                throw new IllegalArgumentException(_loc.get("bad-query-hint-value", key, value).toString());
+            }
+            plan.setHint(key, v);
+        } else if (QueryHints.HINT_INVALIDATE_PREPARED_QUERY.equals(key)) {
+            plan.setHint(key, Filters.convert(value, Boolean.class));
             owner.invalidatePreparedQuery();
-            objectSet = false;
-        } else if (HINT_IGNORE_PREPARED_QUERY.equals(key)) {
-            fPlan.setHint(key, Filters.convert(value, Boolean.class));
+        } else if (QueryHints.HINT_IGNORE_PREPARED_QUERY.equals(key)) {
+            plan.setHint(key, Filters.convert(value, Boolean.class));
             owner.ignorePreparedQuery();
-            objectSet = false;
         } else { // default 
-            fPlan.setHint(key, value);
-            objectSet = false;
+            plan.setHint(key, value);
         }
-        return objectSet;
     }
-
-    protected String hintToKey(String key) {
-        // Let superclass performs key transformation when fPlan.setHint() 
-        // is called.
-        return key;
+    
+    /**
+     * Affirms if the given key starts with any of the known prefix.
+     * @param key
+     * @return
+     */
+    protected boolean isKnownPrefix(String key) {
+        if (key == null)
+            return false;
+        for (String prefix : ProductDerivations.getConfigurationPrefixes()) {
+            if (key.startsWith(prefix))
+                return true;
+        }
+        return false;
     }
 
-    private 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;
+    
+    
+//    protected boolean hasPrecedent(String key) {
+//        boolean hasPrecedent = true;
+//        String[] list = precedenceMap.get(key);
+//        if (list != null) {
+//            for (String hint : list) {
+//                if (hint.equals(key))
+//                    break;
+//                // stop if a higher precedence hint has already defined 
+//                if (getHints().containsKey(hint)) {
+//                    hasPrecedent = false;
+//                    break;
+//                }
+//            }
+//        }
+//        return hasPrecedent;
+//    }
+
+//    private Integer toLockLevel(Object value) {
+//        Object origValue = value;
+//        if (value instanceof String) {
+//            // to accommodate alias name input in relationship with enum values
+//            //  e.g. "optimistic-force-increment" == LockModeType.OPTIMISTIC_FORCE_INCREMENT
+//            String strValue = ((String) value).toUpperCase().replace('-', '_');
+//            value = Enum.valueOf(LockModeType.class, strValue);
+//        }
+//        if (value instanceof LockModeType)
+//            value = MixedLockLevelsHelper.toLockLevel((LockModeType) value);
+//
+//        Integer intValue = null;
+//        if (value instanceof Integer)
+//            intValue = (Integer) value;
+//        if (intValue == null
+//            || (intValue != MixedLockLevels.LOCK_NONE
+//                && intValue != MixedLockLevels.LOCK_READ
+//                && intValue != MixedLockLevels.LOCK_OPTIMISTIC
+//                && intValue != MixedLockLevels.LOCK_WRITE
+//                && intValue != MixedLockLevels.LOCK_OPTIMISTIC_FORCE_INCREMENT
+//                && intValue != MixedLockLevels.LOCK_PESSIMISTIC_READ
+//                && intValue != MixedLockLevels.LOCK_PESSIMISTIC_WRITE
+//                && intValue != MixedLockLevels.LOCK_PESSIMISTIC_FORCE_INCREMENT)
+//                )
+//            throw new IllegalArgumentException(_loc.get("bad-lock-level", origValue).getMessage());
+//        return intValue;
+//    }
+    
+    /**
+     * Gets all the supported hint keys. The set of supported hint keys is
+     * statically determined by collecting hint keys from the ProductDerivations.
+     */
+    public Set<String> getSupportedHints() {
+        return _supportedHints;
     }
+    
+    /**
+     * Gets all the recorded hint keys and their values.
+     */
+    public Map<String, Object> getHints() {
+        if (_hints == null)
+            return Collections.emptyMap();
+        return Collections.unmodifiableMap(_hints);
+    }
+
 }
 

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEnum.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEnum.java?rev=899530&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEnum.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEnum.java Fri Jan 15 05:25:25 2010
@@ -0,0 +1,53 @@
+/*
+ * 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.persistence;
+
+/**
+ * An interface to define conversion of a facade based enum to a kernel integer constant.
+ * Facade specific enums implement this interface to convert user specified string or integer.
+ * 
+ * @author Pinaki Poddar
+ * @since 2.0.0
+ * 
+ * @param <E> the enum type that needs to be converted. 
+ */
+public interface OpenJPAEnum<E extends Enum<?>> {
+    /**
+     * Convert this receiver to an equivalent kernel constant.
+     */
+    int toKernelConstant();
+    
+    /**
+     * Convert the given integer to an equivalent kernel constant.
+     * This method has a <em>static</em> semantics in the sense that it can be invoked on any enum instance, 
+     * but the conversion is done w.r.t. all enums of the generic type. 
+     * 
+     * @exception throw IllegalArgumentException if no enum instance of the generic type matches the given integer. 
+     */
+    int convertToKernelConstant(int i);
+
+    /**
+     * Convert the given String to an equivalent kernel constant.
+     * This method has a <em>static</em> semantics in the sense that it can be invoked on any enum instance, 
+     * but the conversion is done w.r.t. all enums of the generic type. 
+     * 
+     * @exception throw IllegalArgumentException if no enum instance of the generic type matches the given String. 
+     */
+    int convertToKernelConstant(String s);
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEnum.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message