openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ppod...@apache.org
Subject svn commit: r694412 - in /openjpa/branches/sql-cache: openjpa-kernel/src/main/java/org/apache/openjpa/conf/ openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/ ope...
Date Thu, 11 Sep 2008 18:47:38 GMT
Author: ppoddar
Date: Thu Sep 11 11:47:36 2008
New Revision: 694412

URL: http://svn.apache.org/viewvc?rev=694412&view=rev
Log:
Refactor package location closer to kernel, add exclusion pattern, add comments

Added:
    openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQuery.java
      - copied, changed from r694111, openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java
    openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQueryCache.java
      - copied, changed from r694135, openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQueryCache.java
    openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQueryCacheImpl.java
    openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryStatistics.java
      - copied, changed from r694135, openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryStatistics.java
    openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCacheExclusion.java
Removed:
    openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java
    openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQueryCache.java
    openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryStatistics.java
Modified:
    openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java
    openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
    openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/PreparedQueryCacheValue.java
    openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
    openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
    openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
    openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java

Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java?rev=694412&r1=694411&r2=694412&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java
(original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java
Thu Sep 11 11:47:36 2008
@@ -29,13 +29,13 @@
 import org.apache.openjpa.event.RemoteCommitProvider;
 import org.apache.openjpa.kernel.AutoClear;
 import org.apache.openjpa.kernel.AutoDetach;
-import org.apache.openjpa.kernel.Broker;
 import org.apache.openjpa.kernel.BrokerFactory;
 import org.apache.openjpa.kernel.BrokerImpl;
 import org.apache.openjpa.kernel.ConnectionRetainModes;
 import org.apache.openjpa.kernel.FetchConfiguration;
 import org.apache.openjpa.kernel.InverseManager;
 import org.apache.openjpa.kernel.LockManager;
+import org.apache.openjpa.kernel.PreparedQueryCache;
 import org.apache.openjpa.kernel.QueryFlushModes;
 import org.apache.openjpa.kernel.RestoreState;
 import org.apache.openjpa.kernel.SavepointManager;
@@ -46,7 +46,6 @@
 import org.apache.openjpa.lib.conf.Configuration;
 import org.apache.openjpa.meta.MetaDataFactory;
 import org.apache.openjpa.meta.MetaDataRepository;
-import org.apache.openjpa.persistence.PreparedQueryCache;
 import org.apache.openjpa.util.ClassResolver;
 import org.apache.openjpa.util.ProxyManager;
 import org.apache.openjpa.util.StoreFacadeTypeRegistry;

Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java?rev=694412&r1=694411&r2=694412&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
(original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
Thu Sep 11 11:47:36 2008
@@ -38,6 +38,7 @@
 import org.apache.openjpa.kernel.InverseManager;
 import org.apache.openjpa.kernel.LockLevels;
 import org.apache.openjpa.kernel.LockManager;
+import org.apache.openjpa.kernel.PreparedQueryCache;
 import org.apache.openjpa.kernel.QueryFlushModes;
 import org.apache.openjpa.kernel.RestoreState;
 import org.apache.openjpa.kernel.SavepointManager;
@@ -49,7 +50,6 @@
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.meta.MetaDataFactory;
 import org.apache.openjpa.meta.MetaDataRepository;
-import org.apache.openjpa.persistence.PreparedQueryCache;
 import org.apache.openjpa.util.ClassResolver;
 import org.apache.openjpa.util.ImplHelper;
 import org.apache.openjpa.util.ProxyManager;

Modified: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/PreparedQueryCacheValue.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/PreparedQueryCacheValue.java?rev=694412&r1=694411&r2=694412&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/PreparedQueryCacheValue.java
(original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/conf/PreparedQueryCacheValue.java
Thu Sep 11 11:47:36 2008
@@ -19,7 +19,6 @@
 package org.apache.openjpa.conf;
 
 import org.apache.openjpa.lib.conf.PluginValue;
-import org.apache.openjpa.persistence.PreparedQueryCache;
 
 /**
  * A cache of prepared queries indexed by an identifier.
@@ -32,7 +31,7 @@
     extends PluginValue {
 
     public static final String[] ALIASES = {
-	    "true", PreparedQueryCache.class.getName(),
+	    "true", "org.apache.openjpa.kernel.PreparedQueryCacheImpl",
 	    "false", null,
     };
 	  

Copied: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQuery.java
(from r694111, openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java)
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQuery.java?p2=openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQuery.java&p1=openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java&r1=694111&r2=694412&rev=694412&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java
(original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQuery.java
Thu Sep 11 11:47:36 2008
@@ -16,76 +16,81 @@
  * specific language governing permissions and limitations
  * under the License.    
  */
-package org.apache.openjpa.persistence;
+package org.apache.openjpa.kernel;
 
-import org.apache.openjpa.kernel.Query;
-import org.apache.openjpa.kernel.QueryHints;
 
 /**
- * A prepared query binds a compiled query to its target SQL. 
+ * A prepared query associates a compiled query to a <em>parsed state</em> that
+ * can be executed possibly with more efficiency. An obvious example is to 
+ * associate a compiled query to an executable SQL string. 
  * 
- * The target SQL is meant to be executed directly bypassing the critical 
- * cost of constructing the SQL on every query execution. As the subsequent 
- * execution of a cached query will bypass compilation as a JPQL query,
- * the post-compilation state of the original query is captured in this receiver
- * to be transferred to the executable query instance.  
+ * The query expressed in target language can be executed directly bypassing 
+ * the critical translation cost to the data store target language on every 
+ * execution. 
  * 
- * The target SQL depends on context of query execution such as fetch plan or
- * lock group. No attempt is made to monitor and automatically invalidate a
- * prepared SQL when the same query is executed with different context 
- * parameters.
+ * As the subsequent execution of a cached query will bypass normal query 
+ * compilation, the post-compilation state of the original query is captured by 
+ * this receiver to be transferred to the executable query instance.  
  * 
- * The user must set a {@link QueryHints#HINT_INVALIDATE_PREPARED_QUERY hint} to 
- * invalidate.
+ * This receiver must not hold any context-sensitive reference or dependency.
+ * Because the whole idea of preparing a query (for a cost) is to be able to
+ * execute the same logical query in different persistence contexts. However,
+ * a prepared query may not be valid when some parameters of execution context  
+ * such as lock group or fetch plan changes in a way that will change the target
+ * query. Refer to {@link PreparedQueryCache} for invalidation mechanism on
+ * possible actions under such circumstances.
+ * 
+ * The query execution model <em>does</em> account for context changes that do

+ * not impact the target query e.g. bind variables. 
  * 
  * @author Pinaki Poddar
  *
  * @since 1.3.0
- * @nojavadoc
  */
 public class PreparedQuery  {
-	private final String _sql;
+	private final String _ex;
 	private final String _id;
 	
-	// Post-compilation state of an executable query
-	Class _candidate = null;
-	boolean _subclasses = true;
-	boolean _isProjection = false;
-	
+	// Post-compilation state of an executable query, populated on construction
+	private Class _candidate;
+	private boolean _subclasses;
+	private boolean _isProjection;
+	
+	/**
+	 * 
+	 * @param id an identifier for this query to be used as cache key
+	 * @param corresponding data store language expression 
+	 * @param compiled a compiled query 
+	 */
 	public PreparedQuery(String id, String sql, Query compiled) {
 		this._id = id;
-		this._sql = sql;
+		this._ex = sql;
 		
-		_candidate = compiled.getCandidateType();
-		_subclasses = compiled.hasSubclasses();
-		_isProjection = compiled.getProjectionAliases().length > 0;
+		if (compiled != null) {
+			_candidate    = compiled.getCandidateType();
+			_subclasses   = compiled.hasSubclasses();
+			_isProjection = compiled.getProjectionAliases().length > 0;
+		}
 	}
 	
 	public String getIdentifier() {
 		return _id;
 	}
 	
-	public String getSQL() {
-		return _sql;
-	}
-	
-	public String toString() {
-		return "PreparedQuery " + _id + "==>" + _sql;
+	public String getDatastoreAction() {
+		return _ex;
 	}
 	
-	void setInto(Query q) {
-//		q.setCandidateCollection(last.getCandidateCollection());
-//		q.setCandidateExtent(last.getCandidateExtent());
-		
+	/**
+	 * Pours the post-compilation state held by this receiver to the given
+	 * query.
+	 */
+	public void setInto(Query q) {
 		if (!_isProjection)
 			q.setCandidateType(_candidate, _subclasses);
-		
-//		q.setIgnoreChanges(last.getIgnoreChanges());
-//		q.setRange(last.getStartRange(), last.getEndRange());
-//		q.setReadOnly(last.isReadOnly());
-//		q.setResultMapping(last.getResultMappingScope(), 
-//		last.getResultMappingName());
-//		q.setResultType(last.getResultType());
-//		q.setUnique(last.isUnique());
+	}
+	
+	public String toString() {
+		return "PreparedQuery: [" + _id + "] --> [" + _ex + "]";
 	}
 }

Copied: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQueryCache.java
(from r694135, openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQueryCache.java)
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQueryCache.java?p2=openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQueryCache.java&p1=openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQueryCache.java&r1=694135&r2=694412&rev=694412&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQueryCache.java
(original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQueryCache.java
Thu Sep 11 11:47:36 2008
@@ -16,222 +16,137 @@
  * specific language governing permissions and limitations
  * under the License.    
  */
-package org.apache.openjpa.persistence;
+package org.apache.openjpa.kernel;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.locks.ReentrantLock;
 
-import org.apache.commons.lang.StringUtils;
-import org.apache.openjpa.kernel.QueryHints;
 import org.apache.openjpa.lib.conf.Configurable;
-import org.apache.openjpa.lib.conf.Configuration;
 
 /**
  * A cache to maintain {@link PreparedQuery prepared queries}. 
  * 
- * The target SQL depends on context of query execution such as fetch plan or
- * lock group. No attempt is made to monitor and automatically invalidate a
- * prepared SQL when the same query is executed with different context 
- * parameters.
+ * The target query associated to a cached prepared query <em>may</em> depend
on 
+ * query execution context such as fetch plan or lock group. This cache, by 
+ * design, does not monitor the context or automatically invalidate an entry
+ * when the query is executed with context parameters that affect the target 
+ * query. 
  * 
- * The user must set a {@link QueryHints#HINT_INVALIDATE_PREPARED_QUERY hint} to 
- * invalidate.
+ * The user must notify this receiver to invalidate a cached entry when context
+ * changes in a way that will modify the resultant target language query.
+ * 
+ * One of the built-in mechanism (available in JPA facade) is to set query hints 
+ * to either invalidate the query entirely or ignore the cached version for the 
+ * current execution. 
+ * 
+ * @see QueryHints#HINT_IGNORE_PREPARED_QUERY 
+ * @see QueryHints#HINT_INVALIDATE_PREPARED_QUERY
+ * 
+ * This cache allows customization of whether a query can be cached or not
+ * via either explicit marking of certain keys as non-cachable (which is 
+ * irreversible) or addition/removal of exclusion patterns (which is reversible).
+ * 
+ * @see #markUncachable(String)
+ * @see #addExclusionPattern(String)
+ * @see #setExcludes(String)
+ * @see #removeExclusionPattern(String)
  * 
  * @author Pinaki Poddar
  *
  * @since 1.3.0
- * @nojavadoc
  */
-public class PreparedQueryCache implements Configurable {
-	private static final String PATTERN_SEPARATOR = "\\;";
+public interface PreparedQueryCache extends Configurable {
 
-	private final Map<String, PreparedQuery> _delegate;
-	private final Set<String> _uncachables;
-	private final QueryStatistics _stats;
-	private List<String> _excludes;
-	private ReentrantLock _lock = new ReentrantLock();
-
-	public PreparedQueryCache() {
-		_delegate = new HashMap<String, PreparedQuery>();
-		_uncachables = new HashSet<String>();
-		_stats = new QueryStatistics.Default();
-	}
-	
 	/**
-	 * Get a map view of the cached SQL indexed by query identifier.
+	 * Get a map view of the cached queries indexed by identifier.
 	 */
-	public Map<String,String> getMapView() {
-		lock();
-		try {
-			Map<String, String> view = new TreeMap<String, String>();
-			for (Map.Entry<String, PreparedQuery> entry : _delegate.entrySet())
-				view.put(entry.getKey(), entry.getValue().getSQL());
-			return view;
-		} finally {
-			unlock();
-		}
-	}
-	
+	public Map<String, String> getMapView();
+
 	/**
 	 * Cache the given PreparedQuery.
 	 * The key is the identifier of the given PreparedQuery itself.
+	 * The query must not be cached if either the key matches any exclusion
+	 * pattern or the key has been marked non-cachable.
+	 * 
+	 * @return true if the given query is cached. false if it can not be cached
+	 * due to exclusion.
+	 * 
+	 * @see #markUncachable(String)
+	 * @see #setExcludes(String)
+	 * @see #addExclusionPattern(String)
 	 */
-	public boolean cache(PreparedQuery q) {
-		lock();
-		try {
-			if (isExcluded(q.getIdentifier())) {
-				markUncachable(q.getIdentifier());
-				return false;
-			}
-			_delegate.put(q.getIdentifier(), q);
-			return true;
-		} finally {
-			unlock();
-		}
-	}
-	
+	public boolean cache(PreparedQuery q);
+
 	/**
-	 * Remove the PreparedQuery with the given identifier.
+	 * Remove the PreparedQuery with the given identifier from this cache.
 	 */
-	public boolean invalidate(String id) {
-		lock();
-		try {
-			return _delegate.remove(id) != null;
-		} finally {
-			unlock();
-		}
-	}
-	
+	public boolean invalidate(String id);
+
 	/**
 	 * Get the PreparedQuery with the given identifier if it exists. null
 	 * otherwise.
 	 */
-	public PreparedQuery get(String id) {
-		lock();
-		try {
-			return _delegate.get(id);
-		} finally {
-			unlock();
-		}
-	}
-	
+	public PreparedQuery get(String id);
+
 	/**
 	 * Affirms if a PreparedQuery can be cached against the given key.
 	 * 
 	 * @return Boolean.FALSE if the given key is explicitly marked before as not
-	 * be cached or matches any of the exclusion pattern. 
-	 * Boolean.TRUE if the given key has been in the cache. 
+	 * be cached or matches any of the exclusion patterns. 
+	 * Boolean.TRUE if the given key currently exists in the cache. 
 	 * Otherwise, return null implying this receiver can not determine whether
 	 * this key can be cached on not. 
+	 * 
 	 */
-	public Boolean isCachable(String id) {
-		lock();
-		try {
-			if (_uncachables.contains(id))
-				return Boolean.FALSE;
-			if (_delegate.containsKey(id))
-				return Boolean.TRUE;
-			return null;
-		} finally {
-			unlock();
-		}
-	}
-	
+	public Boolean isCachable(String id);
+
 	/**
 	 * Marks the given key as not amenable to caching.
-	 * Marking helps to avoid repeated computational cost of determining whether 
-	 * a query can be cached or not.
+	 * Explicit marking helps to avoid repeated computational cost of 
+	 * determining whether a query can be cached or not.
+	 * 
+	 * Explicit marking can not be reversed by removal of exclusion patterns.
+	 * 
 	 * @return The value for the given key if it had been cached before. null
 	 * otherwise.
 	 */
-	public PreparedQuery markUncachable(String id) {
-		lock();
-		try {
-			_uncachables.add(id);
-			return _delegate.remove(id);
-		} finally {
-			unlock();
-		}
-	}
+	public PreparedQuery markUncachable(String id);
+
+	/**
+	 * Affirms if the given key matches any of the exclusion patterns.
+	 */
+	public boolean isExcluded(String id);
+
+	/**
+	 * Gets the exclusion patterns.
+	 */
+	public List<String> getExcludes();
 	
-	public boolean isExcluded(String id) {
-		lock();
-		try {
-			if (_excludes == null || _excludes.isEmpty())
-				return false;
-			for (String exclude : _excludes)
-				if (exclude.equalsIgnoreCase(id) || exclude.matches(id))
-					return true;
-			return false;
-		} finally {
-			unlock();
-		}
-	}
+	/**
+	 * Sets one or more exclusion regular expression patterns separated by 
+	 * semicolon. Any existing cache entry whose key matches any of the given
+	 * pattern will be marked non-cachable in a reversible manner. 
+	 */
+	public void setExcludes(String excludes);
+
+	/**
+	 * Adds the given pattern to the list of excluded patterns. Any existing 
+	 * cache entry whose key matches the given pattern will be marked 
+	 * non-cachable in a reversible manner. 
+	 */
+	public void addExclusionPattern(String pattern);
 	
-	public QueryStatistics getStatistics() {
-		return _stats;
-	}
+	/**
+	 * Removes the given pattern from the list of excluded patterns. 
+	 * Any excluded key that matches the given pattern can now be cached
+	 * again, unless it has been marked non-cachable explicitly.
+	 * 
+	 * @see #markUncachable(String)
+	 */
+	public void removeExclusionPattern(String pattern);
 	
-    void lock() {
-        if (_lock != null)
-            _lock.lock();
-    }
-
-    void unlock() {
-        if (_lock != null && _lock.isLocked())
-            _lock.unlock();
-    }
-
-	//-------------------------------------------------------
-	// Configurable implementation
-	//-------------------------------------------------------
-    /**
-     * Invoked prior to setting bean properties.
-     */
-    public void setConfiguration(Configuration conf) {
-    }
-
-    /**
-     * Invoked before bean property configuration is begun on this object.
-     */
-    public void startConfiguration() {
-    	
-    }
-
-    /**
-     * Invoked upon completion of bean property configuration for this object.
-     */
-    public void endConfiguration() {
-    	
-    }
-    
-    /**
-     * Sets one or more exclusion patterns separated by semicolon.
-     */
-	public void setExcludes(String excludes) {
-		lock();
-		try {
-			if (StringUtils.isEmpty(excludes))
-				return;
-			if (_excludes == null)
-				_excludes = new ArrayList<String>();
-			String[] patterns = excludes.split(PATTERN_SEPARATOR);
-			_excludes.addAll(Arrays.asList(patterns));
-		} finally {
-			unlock();
-		}
-	}
-
-	public List<String> getExcludes() {
-		return _excludes == null ? Collections.EMPTY_LIST : 
-			Collections.unmodifiableList(_excludes);
-	}
-}
+	/**
+	 * Gets the simple statistics for executed queries.
+	 */
+	public QueryStatistics getStatistics();
+}
\ No newline at end of file

Added: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQueryCacheImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQueryCacheImpl.java?rev=694412&view=auto
==============================================================================
--- openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQueryCacheImpl.java
(added)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PreparedQueryCacheImpl.java
Thu Sep 11 11:47:36 2008
@@ -0,0 +1,278 @@
+/*
+ * 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.kernel;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.openjpa.lib.conf.Configuration;
+
+/**
+ * An implementation of the cache of {@link PreparedQuery prepared queries}. 
+ * 
+ * @author Pinaki Poddar
+ *
+ * @since 1.3.0
+ * @nojavadoc
+ */
+public class PreparedQueryCacheImpl implements PreparedQueryCache {
+	private static final String PATTERN_SEPARATOR = "\\;";
+	private static final String EXLUDED_BY_USER = "Excluded by user";
+	
+	// Key: Query identifier 
+	private final Map<String, PreparedQuery> _delegate;
+	// Key: Query identifier Value: Reason why excluded
+	private final Map<String, String> _uncachables;
+	private List<String> _exclusionPatterns;
+	private final QueryStatistics _stats;
+	private ReentrantLock _lock = new ReentrantLock();
+
+	public PreparedQueryCacheImpl() {
+		_delegate = new HashMap<String, PreparedQuery>();
+		_uncachables = new HashMap<String, String>();
+		_stats = new QueryStatistics.Default();
+	}
+	
+	public Map<String,String> getMapView() {
+		lock();
+		try {
+			Map<String, String> view = new TreeMap<String, String>();
+			for (Map.Entry<String, PreparedQuery> entry : _delegate.entrySet())
+				view.put(entry.getKey(), entry.getValue().getDatastoreAction());
+			return view;
+		} finally {
+			unlock();
+		}
+	}
+	
+	/**
+	 * Cache the given query keyed by its identifier. Does not cache if the 
+	 * identifier matches any exclusion pattern or has been marked as 
+	 * non-cachable. Also register the identifier as not cachable against 
+	 * the matched exclusion pattern.
+	 */
+	public boolean cache(PreparedQuery q) {
+		lock();
+		try {
+			String id = q.getIdentifier();
+			if (isCachable(id) == Boolean.FALSE)
+				return false;
+			String pattern = getMatchedExclusionPattern(id);
+			if (pattern != null) {
+				markUncachable(q.getIdentifier(), pattern);
+				return false;
+			}
+			_delegate.put(q.getIdentifier(), q);
+			return true;
+		} finally {
+			unlock();
+		}
+	}
+	
+	public boolean invalidate(String id) {
+		lock();
+		try {
+			return _delegate.remove(id) != null;
+		} finally {
+			unlock();
+		}
+	}
+	
+	public PreparedQuery get(String id) {
+		lock();
+		try {
+			return _delegate.get(id);
+		} finally {
+			unlock();
+		}
+	}
+	
+	public Boolean isCachable(String id) {
+		lock();
+		try {
+			if (_uncachables.containsKey(id))
+				return Boolean.FALSE;
+			if (_delegate.containsKey(id))
+				return Boolean.TRUE;
+			return null;
+		} finally {
+			unlock();
+		}
+	}
+	
+	public PreparedQuery markUncachable(String id) {
+		return markUncachable(id, EXLUDED_BY_USER);
+	}
+	
+	private PreparedQuery markUncachable(String id, String pattern) {
+		lock();
+		try {
+			if (_uncachables.get(id) != EXLUDED_BY_USER)
+				_uncachables.put(id, pattern);
+			return _delegate.remove(id);
+		} finally {
+			unlock();
+		}
+	}
+	
+	public boolean isExcluded(String id) {
+		return getMatchedExclusionPattern(id) != null;
+	}
+	
+	public void setExcludes(String excludes) {
+		lock();
+		try {
+			if (StringUtils.isEmpty(excludes))
+				return;
+			if (_exclusionPatterns == null)
+				_exclusionPatterns = new ArrayList<String>();
+			String[] patterns = excludes.split(PATTERN_SEPARATOR);
+			for (String pattern : patterns)
+				addExclusionPattern(pattern);
+		} finally {
+			unlock();
+		}
+	}
+
+	public List<String> getExcludes() {
+		return _exclusionPatterns == null ? Collections.EMPTY_LIST : 
+			Collections.unmodifiableList(_exclusionPatterns);
+	}
+	
+	/**
+	 * Adds a pattern for exclusion. Any query cached currently whose identifier
+	 * matches the given pattern will be marked invalidated as a side-effect.
+	 */
+	public void addExclusionPattern(String pattern) {
+		lock();
+		try {
+			if (_exclusionPatterns == null)
+				_exclusionPatterns = new ArrayList<String>();
+			_exclusionPatterns.add(pattern);
+			Collection<String> invalidKeys = getMatchedKeys(pattern, 
+					_delegate.keySet());
+			for (String invalidKey : invalidKeys)
+				markUncachable(invalidKey, pattern);
+		} finally {
+			unlock();
+		}
+	}
+	
+	/**
+	 * Removes a pattern for exclusion. Any query identifier marked as not 
+	 * cachable due to the given pattern will now be removed from the list of
+	 * uncachables as a side-effect.
+	 */
+	public void removeExclusionPattern(String pattern) {
+		lock();
+		try {
+			if (_exclusionPatterns == null)
+				return;
+			_exclusionPatterns.remove(pattern);
+			Collection<String> rebornKeys = getMatchedKeys(pattern, _uncachables);
+			for (String rebornKey : rebornKeys)
+				_uncachables.remove(rebornKey);
+		} finally {
+			unlock();
+		}
+	}
+	
+	public QueryStatistics getStatistics() {
+		return _stats;
+	}
+	
+	/**
+	 * Gets the pattern that matches the given identifier.
+	 */
+	private String getMatchedExclusionPattern(String id) {
+		lock();
+		try {
+			if (_exclusionPatterns == null || _exclusionPatterns.isEmpty())
+				return null;
+			for (String pattern : _exclusionPatterns)
+				if (matches(pattern, id))
+					return pattern;
+			return null;
+		} finally {
+			unlock();
+		}
+	}
+	
+	/**
+	 * Gets the keys of the given map whose values match the given pattern. 
+	 */
+	private Collection<String> getMatchedKeys(String pattern, 
+			Map<String,String> map) {
+		List<String> result = new ArrayList<String>();
+		for (Map.Entry<String, String> entry : map.entrySet()) {
+			if (matches(pattern, entry.getValue())) {
+				result.add(entry.getKey());
+			}
+		}
+		return result;
+	}
+	
+	/**
+	 * Gets the elements of the given list which match the given pattern. 
+	 */
+	private Collection<String> getMatchedKeys(String pattern, 
+			Collection<String> coll) {
+		List<String> result = new ArrayList<String>();
+		for (String key : coll) {
+			if (matches(pattern, key)) {
+				result.add(key);
+			}
+		}
+		return result;
+	}
+
+    void lock() {
+        if (_lock != null)
+            _lock.lock();
+    }
+
+    void unlock() {
+        if (_lock != null && _lock.isLocked())
+            _lock.unlock();
+    }
+    
+    boolean matches(String pattern, String target) {
+    	return target != null && (target.equals(pattern) 
+    	  || target.matches(pattern));
+    }
+    
+	//-------------------------------------------------------
+	// Configurable contract
+	//-------------------------------------------------------
+    public void setConfiguration(Configuration conf) {
+    }
+
+    public void startConfiguration() {
+    }
+
+    public void endConfiguration() {
+    }
+}

Copied: openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryStatistics.java
(from r694135, openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryStatistics.java)
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryStatistics.java?p2=openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryStatistics.java&p1=openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryStatistics.java&r1=694135&r2=694412&rev=694412&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryStatistics.java
(original)
+++ openjpa/branches/sql-cache/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryStatistics.java
Thu Sep 11 11:47:36 2008
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.    
  */
-package org.apache.openjpa.persistence;
+package org.apache.openjpa.kernel;
 
 import java.io.Serializable;
 import java.util.Date;
@@ -26,6 +26,11 @@
 /**
  * Records query execution statistics.
  * 
+ * Statistics can be reset.
+ * 
+ * Gathers both accumulated statistics since start as well as statistics since
+ * last reset.
+ *  
  * @since 1.3.0
  * 
  * @author Pinaki Poddar
@@ -103,9 +108,9 @@
 			return getCount(astats, query, READ);
 		}
 
-		private long getCount(Map<String, long[]> target, String query, int index) {
+		private long getCount(Map<String, long[]> target, String query, int i) {
 			long[] row = target.get(query);
-			return (row == null) ? 0 : row[index];
+			return (row == null) ? 0 : row[i];
 		}
 
 		public Date since() {
@@ -129,12 +134,12 @@
 			addSample(astats, query, index);
 		}
 		
-		private void addSample(Map<String, long[]> target, String query, int index) {
+		private void addSample(Map<String, long[]> target, String query, int i) {
 			long[] row = target.get(query);
 			if (row == null) {
 				row = new long[1];
 			}
-			row[index]++;
+			row[i]++;
 			target.put(query, row);
 		}
 		

Modified: openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java?rev=694412&r1=694411&r2=694412&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
(original)
+++ openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
Thu Sep 11 11:47:36 2008
@@ -21,18 +21,15 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-
-import javax.persistence.EntityManager;
 
 import org.apache.openjpa.conf.OpenJPAConfiguration;
+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.jpql.JPQLParser;
 import org.apache.openjpa.persistence.OpenJPAEntityManager;
 import org.apache.openjpa.persistence.OpenJPAQuery;
-import org.apache.openjpa.persistence.PreparedQuery;
-import org.apache.openjpa.persistence.PreparedQueryCache;
 import org.apache.openjpa.persistence.test.SingleEMFTestCase;
 
 /**
@@ -90,7 +87,6 @@
 	}
 	
 	public void testExclusionPattern() {
-		List<String> patterns = getCache().getExcludes(); 
 		OpenJPAEntityManager em = emf.createEntityManager();
 		OpenJPAQuery q1 = em.createQuery(EXCLUDED_QUERY_1);
 		q1.getResultList();
@@ -129,13 +125,13 @@
 		assertNotCached(jpql);
 		assertLanguage(q1, JPQLParser.LANG_JPQL);
 		
-		List result = q1.getResultList();
+		q1.getResultList();
 		assertCached(jpql);
 		assertLanguage(q1, JPQLParser.LANG_JPQL);
 		
 		PreparedQuery cached = getCache().get(jpql);
 		assertEquals(jpql, cached.getIdentifier());
-		assertNotEquals(jpql, cached.getSQL());
+		assertNotEquals(jpql, cached.getDatastoreAction());
 	}
 
 	public void testPreparedQueryIsCachedAcrossExecution() {
@@ -146,7 +142,7 @@
 		assertLanguage(q1, JPQLParser.LANG_JPQL);
 		
 		
-		List result = q1.getResultList();
+		q1.getResultList();
 		assertCached(jpql);
 		assertLanguage(q1, JPQLParser.LANG_JPQL);
 		
@@ -162,7 +158,8 @@
 		OpenJPAEntityManager em = emf.createEntityManager();
 		OpenJPAQuery q1 = em.createQuery(jpql);
 		assertNotCached(jpql);
-		List result = q1.getResultList();
+		
+		q1.getResultList();
 		assertCached(jpql);
 		assertLanguage(q1, JPQLParser.LANG_JPQL);
 		
@@ -192,7 +189,8 @@
 		OpenJPAEntityManager em = emf.createEntityManager();
 		OpenJPAQuery q1 = em.createQuery(jpql);
 		assertNotCached(jpql);
-		List result = q1.getResultList();
+		
+		q1.getResultList();
 		assertCached(jpql);
 		assertLanguage(q1, JPQLParser.LANG_JPQL);
 		
@@ -330,7 +328,7 @@
 		if (cache == null)
 			return "null";
 		if (cache.get(jpql) != null)
-			return cache.get(jpql).getSQL();
+			return cache.get(jpql).getDatastoreAction();
 		return "null";
 	}
 

Added: openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCacheExclusion.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCacheExclusion.java?rev=694412&view=auto
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCacheExclusion.java
(added)
+++ openjpa/branches/sql-cache/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCacheExclusion.java
Thu Sep 11 11:47:36 2008
@@ -0,0 +1,123 @@
+/*
+ * 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.jdbc.sqlcache;
+
+import java.util.Map;
+
+import org.apache.openjpa.kernel.PreparedQuery;
+import org.apache.openjpa.kernel.PreparedQueryCache;
+import org.apache.openjpa.kernel.PreparedQueryCacheImpl;
+
+import junit.framework.TestCase;
+
+/**
+ * Test exclusion patterns of PreparedQueryCache in isolation.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class TestPreparedQueryCacheExclusion extends TestCase {
+	private PreparedQueryCache cache;
+	private String[] keys   = {"jpql1", "jpql2", "jpql3"};
+	private String[] values = {"sql1", "sql2", "sql3"};
+	
+	protected void setUp() throws Exception {
+		super.setUp();
+		cache = new PreparedQueryCacheImpl();
+		for (int i = 0; i < keys.length; i++) {
+			PreparedQuery p = new PreparedQuery(keys[i], values[i], null);
+			cache.cache(p);
+		}
+	}
+
+	protected void tearDown() throws Exception {
+		super.tearDown();
+	}
+	
+	public void testExclusionPatternsAreSet() {
+		String excludes = "a;b;c";
+		cache.setExcludes(excludes);
+		assertEquals(3, cache.getExcludes().size());
+		assertTrue(cache.isExcluded("a"));
+		assertTrue(cache.isExcluded("b"));
+		assertTrue(cache.isExcluded("c"));
+		assertFalse(cache.isExcluded("d"));
+	}
+
+	public void testCachePopulationSetUp() {
+		assertContent(keys, values);
+	}
+	
+	public void testAddExclusionPatternDisallowsCacheing() {
+		int EXCLUDED = 1;
+		cache.addExclusionPattern(keys[EXCLUDED]);
+		
+		PreparedQuery p = new PreparedQuery(keys[EXCLUDED], values[EXCLUDED], null);
+		assertFalse("Must not cache excluded key " + keys[EXCLUDED], cache.cache(p));
+	}
+
+	public void testAddExclusionPatternMakesExistingEntryInvalid() {
+		int EXCLUDED = 1;
+		cache.addExclusionPattern(keys[EXCLUDED]);
+		Map<String, String> view = cache.getMapView();
+		for (int i = 0; i < keys.length; i++) {
+			if (i == EXCLUDED) {
+				assertFalse(view.containsKey(keys[i]));
+				assertFalse(view.containsValue(values[i]));
+			} else {
+				assertTrue(view.containsKey(keys[i]));
+				assertTrue(view.containsValue(values[i]));
+			}
+		}
+	}
+	
+	public void testRemoveExclusionPatternAllowsCacheing() {
+		int EXCLUDED = 1;
+		cache.addExclusionPattern(keys[EXCLUDED]);
+		
+		PreparedQuery p = new PreparedQuery(keys[EXCLUDED], values[EXCLUDED], null);
+		assertFalse("Must not cache excluded key " + keys[EXCLUDED], cache.cache(p));
+		
+		cache.removeExclusionPattern(keys[EXCLUDED]);
+		assertTrue("Must cache remove excluded key " + keys[EXCLUDED], cache.cache(p));
+	}
+
+	public void testRemoveExclusionPatternDoesNotRemoveUserProhbitedKeys() {
+		String USER_MARKED_UNCACHABLE = "[user prohibited]";
+		cache.markUncachable(USER_MARKED_UNCACHABLE);
+		
+		PreparedQuery p = new PreparedQuery(USER_MARKED_UNCACHABLE, "xyz", null);
+		assertFalse("Must not cache user-prohibited key " + 
+				USER_MARKED_UNCACHABLE, cache.cache(p));
+		
+		cache.removeExclusionPattern(USER_MARKED_UNCACHABLE);
+		assertFalse("Must not cache user-prohibited key even when removed " + 
+				USER_MARKED_UNCACHABLE, cache.cache(p));
+	}
+
+	void assertContent(String[] keys, String[] values) {
+		Map<String, String> view = cache.getMapView();
+		for (int i = 0; i < keys.length; i++) {
+			assertTrue("key " + keys[i] + " not in " + view, 
+					view.containsKey(keys[i]));
+			assertTrue("value " + values[i] + " not in " + view,
+					view.containsValue(values[i]));
+		}
+	}
+}

Modified: openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java?rev=694412&r1=694411&r2=694412&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
(original)
+++ openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
Thu Sep 11 11:47:36 2008
@@ -67,7 +67,6 @@
     private transient Constructor<FetchPlan> _plan = null;
     private transient StoreCache _cache = null;
     private transient QueryResultCache _queryCache = null;
-    private transient Map<String, PreparedQuery> _sqlQueryCache = null;
 
     /**
      * Default constructor provided for auto-instantiation.

Modified: openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java?rev=694412&r1=694411&r2=694412&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
(original)
+++ openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
Thu Sep 11 11:47:36 2008
@@ -50,6 +50,8 @@
 import org.apache.openjpa.kernel.LockLevels;
 import org.apache.openjpa.kernel.OpCallbacks;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.PreparedQuery;
+import org.apache.openjpa.kernel.PreparedQueryCache;
 import org.apache.openjpa.kernel.QueryFlushModes;
 import org.apache.openjpa.kernel.QueryLanguages;
 import org.apache.openjpa.kernel.Seq;
@@ -871,7 +873,7 @@
             PreparedQuery cached = getPreparedQuery(qid);
             if (cached != null) {
                 language = QueryLanguages.LANG_PREPARED_SQL;
-                query = cached.getSQL();
+                query = cached.getDatastoreAction();
             }
             org.apache.openjpa.kernel.Query q = _broker.newQuery(language, 
                 query);

Modified: openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java?rev=694412&r1=694411&r2=694412&view=diff
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
(original)
+++ openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/QueryImpl.java
Thu Sep 11 11:47:36 2008
@@ -39,6 +39,8 @@
 import org.apache.openjpa.kernel.DelegatingQuery;
 import org.apache.openjpa.kernel.DelegatingResultList;
 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;



Mime
View raw message