You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pp...@apache.org on 2008/09/09 04:03:38 UTC

svn commit: r693341 [2/2] - in /openjpa/branches/sql-cache: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-kerne...

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=693341&r1=693340&r2=693341&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 Mon Sep  8 19:03:37 2008
@@ -1,335 +1,358 @@
-/*
- * 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;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import javax.persistence.EntityManagerFactory;
-
-import org.apache.openjpa.conf.OpenJPAConfiguration;
-import org.apache.openjpa.enhance.Reflection;
-import org.apache.openjpa.kernel.AutoDetach;
-import org.apache.openjpa.kernel.Broker;
-import org.apache.openjpa.kernel.BrokerFactory;
-import org.apache.openjpa.kernel.DelegatingBrokerFactory;
-import org.apache.openjpa.kernel.DelegatingFetchConfiguration;
-import org.apache.openjpa.kernel.FetchConfiguration;
-import org.apache.openjpa.lib.conf.Configurations;
-import org.apache.openjpa.lib.conf.ProductDerivations;
-import org.apache.openjpa.lib.conf.Value;
-import org.apache.openjpa.lib.util.Localizer;
-import org.apache.openjpa.lib.util.Closeable;
-import org.apache.openjpa.util.OpenJPAException;
-import serp.util.Strings;
-
-/**
- * Implementation of {@link EntityManagerFactory} that acts as a
- * facade to a {@link BrokerFactory}.
- *
- * @author Marc Prud'hommeaux
- * @nojavadoc
- */
-public class EntityManagerFactoryImpl
-    implements OpenJPAEntityManagerFactory, OpenJPAEntityManagerFactorySPI,
-    Closeable {
-
-    private static final Localizer _loc = Localizer.forPackage
-        (EntityManagerFactoryImpl.class);
-
-    private DelegatingBrokerFactory _factory = null;
-    private transient Constructor<FetchPlan> _plan = null;
-    private transient StoreCache _cache = null;
-    private transient QueryResultCache _queryCache = null;
-
-    /**
-     * Default constructor provided for auto-instantiation.
-     */
-    public EntityManagerFactoryImpl() {
-    }
-
-    /**
-     * Supply delegate on construction.
-     */
-    public EntityManagerFactoryImpl(BrokerFactory factory) {
-        setBrokerFactory(factory);
-    }
-
-    /**
-     * Delegate.
-     */
-    public BrokerFactory getBrokerFactory() {
-        return _factory.getDelegate();
-    }
-
-    /**
-     * Delegate must be provided before use.
-     */
-    public void setBrokerFactory(BrokerFactory factory) {
-        _factory = new DelegatingBrokerFactory(factory,
-            PersistenceExceptions.TRANSLATOR);
-    }
-
-    public OpenJPAConfiguration getConfiguration() {
-        return _factory.getConfiguration();
-    }
-
-    public Properties getProperties() {
-        return _factory.getProperties();
-    }
-
-    public Object putUserObject(Object key, Object val) {
-        return _factory.putUserObject(key, val);
-    }
-
-    public Object getUserObject(Object key) {
-        return _factory.getUserObject(key);
-    }
-
-    public StoreCache getStoreCache() {
-        _factory.lock();
-        try {
-            if (_cache == null) {
-                OpenJPAConfiguration conf = _factory.getConfiguration();
-                _cache = new StoreCacheImpl(this,
-                    conf.getDataCacheManagerInstance().getSystemDataCache());
-            }
-            return _cache;
-        } finally {
-            _factory.unlock();
-        }
-    }
-
-    public StoreCache getStoreCache(String cacheName) {
-        return new StoreCacheImpl(this, _factory.getConfiguration().
-            getDataCacheManagerInstance().getDataCache(cacheName, true));
-    }
-
-    public QueryResultCache getQueryResultCache() {
-        _factory.lock();
-        try {
-            if (_queryCache == null)
-                _queryCache = new QueryResultCacheImpl(_factory.
-                    getConfiguration().getDataCacheManagerInstance().
-                    getSystemQueryCache());
-            return _queryCache;
-        } finally {
-            _factory.unlock();
-        }
-    }
-
-    public OpenJPAEntityManagerSPI createEntityManager() {
-        return createEntityManager(null);
-    }
-
-    public OpenJPAEntityManagerSPI createEntityManager(Map props) {
-        if (props == null)
-            props = Collections.EMPTY_MAP;
-        else if (!props.isEmpty())
-            props = new HashMap(props);
-
-        OpenJPAConfiguration conf = getConfiguration();
-        String user = (String) Configurations.removeProperty
-            ("ConnectionUserName", props);
-        if (user == null)
-            user = conf.getConnectionUserName();
-        String pass = (String) Configurations.removeProperty
-            ("ConnectionPassword", props);
-        if (pass == null)
-            pass = conf.getConnectionPassword();
-
-        String str = (String) Configurations.removeProperty
-            ("TransactionMode", props);
-        boolean managed;
-        if (str == null)
-            managed = conf.isTransactionModeManaged();
-        else {
-            Value val = conf.getValue("TransactionMode");
-            managed = Boolean.parseBoolean(val.unalias(str));
-        }
-
-        Object obj = Configurations.removeProperty("ConnectionRetainMode", 
-            props);
-        int retainMode;
-        if (obj instanceof Number)
-            retainMode = ((Number) obj).intValue();
-        else if (obj == null)
-            retainMode = conf.getConnectionRetainModeConstant();
-        else {
-            Value val = conf.getValue("ConnectionRetainMode");
-            try {
-                retainMode = Integer.parseInt(val.unalias((String) obj));
-            } catch (Exception e) {
-                throw new ArgumentException(_loc.get("bad-em-prop",
-                    "openjpa.ConnectionRetainMode", obj),
-                    new Throwable[]{ e }, obj, true);
-            }
-        }
-
-        Broker broker = _factory.newBroker(user, pass, managed, retainMode,
-            false);
-            
-        // add autodetach for close and rollback conditions to the configuration
-        broker.setAutoDetach(AutoDetach.DETACH_CLOSE, true);
-        broker.setAutoDetach(AutoDetach.DETACH_ROLLBACK, true);
-        
-        broker.setDetachedNew(false);
-        OpenJPAEntityManagerSPI em = newEntityManagerImpl(broker);
-
-        // allow setting of other bean properties of EM
-        String[] prefixes = ProductDerivations.getConfigurationPrefixes();
-        List<RuntimeException> errs = null;
-        Method setter;
-        String prop, prefix;
-        Object val;
-        for (Map.Entry entry : (Set<Map.Entry>) props.entrySet()) {
-            prop = (String) entry.getKey();
-            prefix = null;
-            for (int i = 0; i < prefixes.length; i++) {
-                prefix = prefixes[i] + ".";
-                if (prop.startsWith(prefix))
-                    break;
-                prefix = null; 
-            } 
-            if (prefix == null)
-                continue; 
-            prop = prop.substring(prefix.length());
-            try {
-                setter = Reflection.findSetter(em.getClass(), prop, true);
-            } catch (OpenJPAException ke) {
-                if (errs == null)
-                    errs = new LinkedList<RuntimeException>();
-                errs.add(PersistenceExceptions.toPersistenceException(ke));
-                continue;
-            }
-
-            val = entry.getValue();
-            try {
-                if (val instanceof String) {
-                    if ("null".equals(val))
-                        val = null;
-                    else
-                        val = Strings.parse((String) val,
-                            setter.getParameterTypes()[0]);
-                }
-                Reflection.set(em, setter, val);
-            } catch (Throwable t) {
-                while (t.getCause() != null)
-                    t = t.getCause();
-                ArgumentException err = new ArgumentException(_loc.get
-                    ("bad-em-prop", prop, entry.getValue()),
-                    new Throwable[]{ t }, null, true);
-                if (errs == null)
-                    errs = new LinkedList<RuntimeException>();
-                errs.add(err);
-            }
-        }
-
-        if (errs != null) {
-            em.close();
-            if (errs.size() == 1)
-                throw errs.get(0);
-            throw new ArgumentException(_loc.get("bad-em-props"),
-                errs.toArray(new Throwable[errs.size()]),
-                null, true);
-        }
-        return em;
-    }
-
-    /**
-     * Create a new entity manager around the given broker.
-     */
-    protected EntityManagerImpl newEntityManagerImpl(Broker broker) {
-        return new EntityManagerImpl(this, broker);
-    }
-
-    public void addLifecycleListener(Object listener, Class... classes) {
-        _factory.addLifecycleListener(listener, classes);
-    }
-
-    public void removeLifecycleListener(Object listener) {
-        _factory.removeLifecycleListener(listener);
-    }
-
-    public void addTransactionListener(Object listener) {
-        _factory.addTransactionListener(listener);
-    }
-
-    public void removeTransactionListener(Object listener) {
-        _factory.removeTransactionListener(listener);
-    }
-
-    public void close() {
-        _factory.close();
-    }
-
-    public boolean isOpen() {
-        return !_factory.isClosed();
-    }
-
-    public int hashCode() {
-        return _factory.hashCode();
-    }
-
-    public boolean equals(Object other) {
-        if (other == this)
-            return true;
-        if (!(other instanceof EntityManagerFactoryImpl))
-            return false;
-        return _factory.equals(((EntityManagerFactoryImpl) other)._factory);
-    }
-
-    /**
-     * Create a store-specific facade for the given fetch configuration.
-	 * If no facade class exists, we use the default {@link FetchPlan}.
-     */
-    FetchPlan toFetchPlan(Broker broker, FetchConfiguration fetch) {
-        if (fetch == null)
-            return null;
-
-        if (fetch instanceof DelegatingFetchConfiguration)
-            fetch = ((DelegatingFetchConfiguration) fetch).
-                getInnermostDelegate();
-
-        try {
-            if (_plan == null) {
-                Class storeType = (broker == null) ? null : broker.
-                    getStoreManager().getInnermostDelegate().getClass();
-                Class cls = _factory.getConfiguration().
-                    getStoreFacadeTypeRegistry().
-                    getImplementation(FetchPlan.class, storeType, 
-                    		FetchPlanImpl.class);
-                _plan = cls.getConstructor(FetchConfiguration.class);
-            }
-            return _plan.newInstance(fetch);
-        } catch (InvocationTargetException ite) {
-            throw PersistenceExceptions.toPersistenceException
-                (ite.getTargetException());
-        } catch (Exception e) {
-            throw PersistenceExceptions.toPersistenceException(e);
-        }
-	}
-}
+/*
+ * 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;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.enhance.Reflection;
+import org.apache.openjpa.kernel.AutoDetach;
+import org.apache.openjpa.kernel.Broker;
+import org.apache.openjpa.kernel.BrokerFactory;
+import org.apache.openjpa.kernel.DelegatingBrokerFactory;
+import org.apache.openjpa.kernel.DelegatingFetchConfiguration;
+import org.apache.openjpa.kernel.FetchConfiguration;
+import org.apache.openjpa.lib.conf.Configurations;
+import org.apache.openjpa.lib.conf.ProductDerivations;
+import org.apache.openjpa.lib.conf.Value;
+import org.apache.openjpa.lib.util.Closeable;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.OpenJPAException;
+
+import serp.util.Strings;
+
+/**
+ * Implementation of {@link EntityManagerFactory} that acts as a
+ * facade to a {@link BrokerFactory}.
+ *
+ * @author Marc Prud'hommeaux
+ * @nojavadoc
+ */
+public class EntityManagerFactoryImpl
+    implements OpenJPAEntityManagerFactory, OpenJPAEntityManagerFactorySPI,
+    Closeable {
+
+    private static final Localizer _loc = Localizer.forPackage
+        (EntityManagerFactoryImpl.class);
+
+    private DelegatingBrokerFactory _factory = null;
+    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.
+     */
+    public EntityManagerFactoryImpl() {
+    }
+
+    /**
+     * Supply delegate on construction.
+     */
+    public EntityManagerFactoryImpl(BrokerFactory factory) {
+        setBrokerFactory(factory);
+    }
+
+    /**
+     * Delegate.
+     */
+    public BrokerFactory getBrokerFactory() {
+        return _factory.getDelegate();
+    }
+
+    /**
+     * Delegate must be provided before use.
+     */
+    public void setBrokerFactory(BrokerFactory factory) {
+        _factory = new DelegatingBrokerFactory(factory,
+            PersistenceExceptions.TRANSLATOR);
+    }
+
+    public OpenJPAConfiguration getConfiguration() {
+        return _factory.getConfiguration();
+    }
+
+    public Properties getProperties() {
+        return _factory.getProperties();
+    }
+
+    public Object putUserObject(Object key, Object val) {
+        return _factory.putUserObject(key, val);
+    }
+
+    public Object getUserObject(Object key) {
+        return _factory.getUserObject(key);
+    }
+
+    public StoreCache getStoreCache() {
+        _factory.lock();
+        try {
+            if (_cache == null) {
+                OpenJPAConfiguration conf = _factory.getConfiguration();
+                _cache = new StoreCacheImpl(this,
+                    conf.getDataCacheManagerInstance().getSystemDataCache());
+            }
+            return _cache;
+        } finally {
+            _factory.unlock();
+        }
+    }
+
+    public StoreCache getStoreCache(String cacheName) {
+        return new StoreCacheImpl(this, _factory.getConfiguration().
+            getDataCacheManagerInstance().getDataCache(cacheName, true));
+    }
+
+    public QueryResultCache getQueryResultCache() {
+        _factory.lock();
+        try {
+            if (_queryCache == null)
+                _queryCache = new QueryResultCacheImpl(_factory.
+                    getConfiguration().getDataCacheManagerInstance().
+                    getSystemQueryCache());
+            return _queryCache;
+        } finally {
+            _factory.unlock();
+        }
+    }
+
+    public OpenJPAEntityManagerSPI createEntityManager() {
+        return createEntityManager(null);
+    }
+
+    public OpenJPAEntityManagerSPI createEntityManager(Map props) {
+        if (props == null)
+            props = Collections.EMPTY_MAP;
+        else if (!props.isEmpty())
+            props = new HashMap(props);
+
+        OpenJPAConfiguration conf = getConfiguration();
+        String user = (String) Configurations.removeProperty
+            ("ConnectionUserName", props);
+        if (user == null)
+            user = conf.getConnectionUserName();
+        String pass = (String) Configurations.removeProperty
+            ("ConnectionPassword", props);
+        if (pass == null)
+            pass = conf.getConnectionPassword();
+
+        String str = (String) Configurations.removeProperty
+            ("TransactionMode", props);
+        boolean managed;
+        if (str == null)
+            managed = conf.isTransactionModeManaged();
+        else {
+            Value val = conf.getValue("TransactionMode");
+            managed = Boolean.parseBoolean(val.unalias(str));
+        }
+
+        Object obj = Configurations.removeProperty("ConnectionRetainMode", 
+            props);
+        int retainMode;
+        if (obj instanceof Number)
+            retainMode = ((Number) obj).intValue();
+        else if (obj == null)
+            retainMode = conf.getConnectionRetainModeConstant();
+        else {
+            Value val = conf.getValue("ConnectionRetainMode");
+            try {
+                retainMode = Integer.parseInt(val.unalias((String) obj));
+            } catch (Exception e) {
+                throw new ArgumentException(_loc.get("bad-em-prop",
+                    "openjpa.ConnectionRetainMode", obj),
+                    new Throwable[]{ e }, obj, true);
+            }
+        }
+
+        Broker broker = _factory.newBroker(user, pass, managed, retainMode,
+            false);
+            
+        // add autodetach for close and rollback conditions to the configuration
+        broker.setAutoDetach(AutoDetach.DETACH_CLOSE, true);
+        broker.setAutoDetach(AutoDetach.DETACH_ROLLBACK, true);
+        
+        broker.setDetachedNew(false);
+        OpenJPAEntityManagerSPI em = newEntityManagerImpl(broker);
+
+        // allow setting of other bean properties of EM
+        String[] prefixes = ProductDerivations.getConfigurationPrefixes();
+        List<RuntimeException> errs = null;
+        Method setter;
+        String prop, prefix;
+        Object val;
+        for (Map.Entry entry : (Set<Map.Entry>) props.entrySet()) {
+            prop = (String) entry.getKey();
+            prefix = null;
+            for (int i = 0; i < prefixes.length; i++) {
+                prefix = prefixes[i] + ".";
+                if (prop.startsWith(prefix))
+                    break;
+                prefix = null; 
+            } 
+            if (prefix == null)
+                continue; 
+            prop = prop.substring(prefix.length());
+            try {
+                setter = Reflection.findSetter(em.getClass(), prop, true);
+            } catch (OpenJPAException ke) {
+                if (errs == null)
+                    errs = new LinkedList<RuntimeException>();
+                errs.add(PersistenceExceptions.toPersistenceException(ke));
+                continue;
+            }
+
+            val = entry.getValue();
+            try {
+                if (val instanceof String) {
+                    if ("null".equals(val))
+                        val = null;
+                    else
+                        val = Strings.parse((String) val,
+                            setter.getParameterTypes()[0]);
+                }
+                Reflection.set(em, setter, val);
+            } catch (Throwable t) {
+                while (t.getCause() != null)
+                    t = t.getCause();
+                ArgumentException err = new ArgumentException(_loc.get
+                    ("bad-em-prop", prop, entry.getValue()),
+                    new Throwable[]{ t }, null, true);
+                if (errs == null)
+                    errs = new LinkedList<RuntimeException>();
+                errs.add(err);
+            }
+        }
+
+        if (errs != null) {
+            em.close();
+            if (errs.size() == 1)
+                throw errs.get(0);
+            throw new ArgumentException(_loc.get("bad-em-props"),
+                errs.toArray(new Throwable[errs.size()]),
+                null, true);
+        }
+        return em;
+    }
+
+    /**
+     * Create a new entity manager around the given broker.
+     */
+    protected EntityManagerImpl newEntityManagerImpl(Broker broker) {
+        return new EntityManagerImpl(this, broker);
+    }
+
+    public void addLifecycleListener(Object listener, Class... classes) {
+        _factory.addLifecycleListener(listener, classes);
+    }
+
+    public void removeLifecycleListener(Object listener) {
+        _factory.removeLifecycleListener(listener);
+    }
+
+    public void addTransactionListener(Object listener) {
+        _factory.addTransactionListener(listener);
+    }
+
+    public void removeTransactionListener(Object listener) {
+        _factory.removeTransactionListener(listener);
+    }
+
+    public void close() {
+        _factory.close();
+    }
+
+    public boolean isOpen() {
+        return !_factory.isClosed();
+    }
+
+    public int hashCode() {
+        return _factory.hashCode();
+    }
+
+    public boolean equals(Object other) {
+        if (other == this)
+            return true;
+        if (!(other instanceof EntityManagerFactoryImpl))
+            return false;
+        return _factory.equals(((EntityManagerFactoryImpl) other)._factory);
+    }
+
+    /**
+     * Create a store-specific facade for the given fetch configuration.
+	 * If no facade class exists, we use the default {@link FetchPlan}.
+     */
+    FetchPlan toFetchPlan(Broker broker, FetchConfiguration fetch) {
+        if (fetch == null)
+            return null;
+
+        if (fetch instanceof DelegatingFetchConfiguration)
+            fetch = ((DelegatingFetchConfiguration) fetch).
+                getInnermostDelegate();
+
+        try {
+            if (_plan == null) {
+                Class storeType = (broker == null) ? null : broker.
+                    getStoreManager().getInnermostDelegate().getClass();
+                Class cls = _factory.getConfiguration().
+                    getStoreFacadeTypeRegistry().
+                    getImplementation(FetchPlan.class, storeType, 
+                    		FetchPlanImpl.class);
+                _plan = cls.getConstructor(FetchConfiguration.class);
+            }
+            return _plan.newInstance(fetch);
+        } catch (InvocationTargetException ite) {
+            throw PersistenceExceptions.toPersistenceException
+                (ite.getTargetException());
+        } catch (Exception e) {
+            throw PersistenceExceptions.toPersistenceException(e);
+        }
+	}
+    
+//    boolean cacheQuery(String qid, PreparedQuery sql) {
+//    	if (!isCacheingSQL())
+//    		return false;
+//    	if (_sqlQueryCache == null)
+//    		_sqlQueryCache = new ConcurrentHashMap<String, PreparedQuery>();
+//    	_sqlQueryCache.put(qid, sql);
+//    	return true;
+//    }
+//    
+//    PreparedQuery getPreparedQuery(String qid) {
+//    	if (!isCacheingSQL())
+//    		return null;
+//    	if (_sqlQueryCache == null)
+//    		return null;
+//    	PreparedQuery result = _sqlQueryCache.get(qid);
+//    	return result;
+//    }
+    
+}

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=693341&r1=693340&r2=693341&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 Mon Sep  8 19:03:37 2008
@@ -64,6 +64,7 @@
 import org.apache.openjpa.meta.SequenceMetaData;
 import org.apache.openjpa.util.Exceptions;
 import org.apache.openjpa.util.ImplHelper;
+import org.apache.openjpa.util.ParameterMap;
 import org.apache.openjpa.util.RuntimeExceptionTranslator;
 import org.apache.openjpa.util.UserException;
 
@@ -868,12 +869,21 @@
     public OpenJPAQuery createQuery(String language, String query) {
         assertNotCloseInvoked();
         try {
+            String qid = query;
+            PreparedQuery cached = getPreparedQuery(qid);
+            if (cached != null) {
+                language = QueryLanguages.LANG_PREPARED_SQL;
+                query = cached.getSQL();
+            }
             org.apache.openjpa.kernel.Query q = _broker.newQuery(language, 
                 query);
             // have to validate JPQL according to spec
             if (JPQLParser.LANG_JPQL.equals(language))
                 q.compile(); 
-            return new QueryImpl(this, _ret, q);
+            if (cached != null) {
+            	cached.setInto(q);
+            }
+            return new QueryImpl(this, _ret, q).setId(qid);
         } catch (RuntimeException re) {
             throw PersistenceExceptions.toPersistenceException(re);
         }
@@ -936,6 +946,16 @@
         if (StringUtils.trimToNull(query) == null)
             throw new ArgumentException(_loc.get("no-sql"), null, null, false);
     }
+    
+    private PreparedQuery getPreparedQuery(String id) {
+    	Map cache = getConfiguration().getPreparedQueryCacheInstance();
+    	if (cache == null)
+    		return null;
+    	Object val = cache.get(id);
+    	if (val == PreparedQuery.NOT_CACHABLE)
+    		return null;
+    	return (PreparedQuery)val;
+    }
 
     public void setFlushMode(FlushModeType flushMode) {
         assertNotCloseInvoked();

Added: 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-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java?rev=693341&view=auto
==============================================================================
--- openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java (added)
+++ openjpa/branches/sql-cache/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PreparedQuery.java Mon Sep  8 19:03:37 2008
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import org.apache.openjpa.kernel.Query;
+
+/**
+ * A prepared query binds a compiled query to its target SQL. 
+ * 
+ * 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.  
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class PreparedQuery  {
+	public static final PreparedQuery NOT_CACHABLE = new PreparedQuery();
+	private final String _sql;
+	private final String _id;
+	
+	// Post-compilation state of an executable query
+	Class _candidate = null;
+	boolean _subclasses = true;
+	boolean _isProjection = false;
+	
+	private PreparedQuery() {
+		_sql  = null;
+		_id  = null;
+	}
+	
+	public PreparedQuery(String id, String sql, Query compiled) {
+		this._id = id;
+		this._sql = sql;
+		
+		_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;
+	}
+	
+	void setInto(Query q) {
+//		q.setCandidateCollection(last.getCandidateCollection());
+//		q.setCandidateExtent(last.getCandidateExtent());
+		
+		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());
+	}
+	
+
+}

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=693341&r1=693340&r2=693341&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 Mon Sep  8 19:03:37 2008
@@ -22,18 +22,13 @@
 import java.lang.reflect.Method;
 import java.sql.Time;
 import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.TreeMap;
 
 import javax.persistence.FlushModeType;
 import javax.persistence.Query;
@@ -51,13 +46,16 @@
 import org.apache.openjpa.lib.rop.ResultList;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.util.ImplHelper;
+import org.apache.openjpa.util.ParameterMap;
 import org.apache.openjpa.util.RuntimeExceptionTranslator;
+import org.apache.openjpa.util.UserException;
 
 /**
  * Implementation of {@link Query} interface.
  * 
  * @author Marc Prud'hommeaux
  * @author Abe White
+ * @author Pinaki Poddar
  * @nojavadoc
  */
 public class QueryImpl implements OpenJPAQuerySPI, Serializable {
@@ -69,17 +67,16 @@
 	private final DelegatingQuery _query;
 	private transient EntityManagerImpl _em;
 	private transient FetchPlan _fetch;
+	private ParameterMap _params;
+	private transient Boolean _cacheable = null;
+	private String _id;
 
-	private Map<String, Object> _named;
-	private Map<Integer, Object> _positional;
-
-	private static Object GAP_FILLER = new Object();
 
 	/**
 	 * Constructor; supply factory exception translator and delegate.
 	 * 
 	 * @param em  The EntityManager which created this query
-	 * @param ret Exception translater for this query
+	 * @param ret Exception translator for this query
 	 * @param query The underlying "kernel" query.
 	 */
 	public QueryImpl(EntityManagerImpl em, RuntimeExceptionTranslator ret,
@@ -246,183 +243,13 @@
 		if (_query.getOperation() != QueryOperations.OP_SELECT)
 			throw new InvalidStateException(_loc.get("not-select-query", _query
 					.getQueryString()), null, null, false);
-
-		validateParameters();
-
-		// handle which types of parameters we are using, if any
-		if (_positional != null)
-			return _query.execute(_positional);
-		if (_named != null)
-			return _query.execute(_named);
-		return _query.execute();
+		PreparedQuery cachedQuery = cache();
+		boolean usingCachedQuery = (cachedQuery != null);
+		validate(_query.getParameterTypes(), !usingCachedQuery);
+		Object result = _query.execute(getParameterMap(usingCachedQuery));
+		return result;
 	}
 	
-	/**
-	 * Validate that the types of the parameters are correct.
-	 * The idea is to catch as many validation error as possible at the facade
-	 * layer itself.
-	 * For native SQL queries, however, parameter validation is bypassed as
-	 * we do not parse SQL.
-	 * 
-	 * The expected parameters are parsed from the query and in a LinkedMap 
-	 *	key   : name of the parameter as declared in query
-	 *  value : expected Class of allowed value
-	 *  
-	 * The bound parameters depends on positional or named parameter style
-	 * 
-	 * TreeMap<Integer, Object> for positional parameters:
-	 *   key   : 1-based Integer index
-	 *   value : bound value. GAP_FILLER if the position is not set. This
-	 *   simplifies validation at the kernel layer
-	 *   
-	 * Map<String, Object> for named parameters:
-	 *   key   : parameter name
-	 *   value : the bound value
-	 *   
-	 *  Validation accounts for 
-	 *    a) gaps in positional parameters
-	 *       SELECT p FROM PObject p WHERE p.a1=?1 AND p.a3=?3
-	 *    
-	 *    b) repeated parameters
-	 *       SELECT p FROM PObject p WHERE p.a1=?1 AND p.a2=?1 AND p.a3=?2
-	 *       
-	 *    c) parameter is bound but not declared
-	 *    
-	 *    d) parameter is declared but not bound
-	 *    
-	 *    e) parameter does not match the value type
-	 *    
-	 *    f) parameter is primitive type but bound to null value
-	 */
-	private void validateParameters() {
-		if (isNative()) {
-			removeGaps(_positional);
-			return;
-		}
-		String query = getQueryString();
-		if (_positional != null) {
-			LinkedMap expected = _query.getParameterTypes();
-			Map<Integer, Object> actual = _positional;
-			for (Object o : expected.keySet()) {
-				String position = (String) o;
-				Class expectedParamType = (Class) expected.get(position);
-				try {
-					Integer.parseInt(position);
-				} catch (NumberFormatException ex) {
-					newValidationException("param-style-mismatch", query,
-							expected.asList(),
-							Arrays.toString(actual.keySet().toArray()));
-				}
-				Object actualValue = actual.get(Integer.parseInt(position));
-				boolean valueUnspecified = (actualValue == GAP_FILLER)
-						|| (actualValue == null && (actual.size() < expected
-								.size()));
-				if (valueUnspecified) 
-					newValidationException("param-missing", position, query,
-							Arrays.toString(actual.keySet().toArray()));
-				
-				if (expectedParamType.isPrimitive() && actualValue == null)
-					newValidationException("param-type-null", 
-							position, query, expectedParamType.getName());
-				if (actualValue != null &&
-				   !Filters.wrap(expectedParamType).isInstance(actualValue)) 
-					newValidationException("param-type-mismatch",
-							position, query, actualValue,
-							actualValue.getClass().getName(),
-							expectedParamType.getName());
-				
-			}
-			for (Integer position : actual.keySet()) {
-				Object actualValue = actual.get(position);
-				Class expectedParamType = (Class) expected.get("" + position);
-				boolean paramExpected = expected.containsKey("" + position);
-				if (actualValue == GAP_FILLER) {
-					if (paramExpected) {
-						newValidationException("param-missing", position, query,
-								Arrays.toString(actual.keySet().toArray()));
-					}
-				} else {
-					if (!paramExpected)
-						newValidationException("param-extra", position, query,
-								expected.asList());
-					if (expectedParamType.isPrimitive() && actualValue == null)
-						newValidationException("param-type-null", 
-								position, query, expectedParamType.getName());
-					if (actualValue != null 
-					 && !Filters.wrap(expectedParamType).isInstance(actualValue)) 
-						newValidationException("param-type-mismatch",
-								position, query, actualValue,
-								actualValue.getClass().getName(),
-								expectedParamType.getName());
-					
-				}
-			}
-
-		} else if (_named != null) {
-			LinkedMap expected = _query.getParameterTypes();
-			// key : name of the parameter used while binding
-			// value : user supplied parameter value. null may mean either
-			// user has supplied a value or not specified at all
-			Map<String, Object> actual = _named;
-			for (Object o : expected.keySet()) {
-				String expectedName = (String) o;
-				Class expectedParamType = (Class) expected.get(expectedName);
-				Object actualValue = actual.get(expectedName);
-				boolean valueUnspecified = !actual.containsKey(expectedName);
-				if (valueUnspecified) {
-					newValidationException("param-missing", expectedName, query,
-							Arrays.toString(actual.keySet().toArray()));
-				}
-				if (expectedParamType.isPrimitive() && actualValue == null)
-					newValidationException("param-type-null", 
-							expectedName, query, expectedParamType.getName());
-				if (actualValue != null 
-				 && !Filters.wrap(expectedParamType).isInstance(actualValue)) {
-					newValidationException("param-type-mismatch",
-							expectedName, query, actualValue,
-							actualValue.getClass().getName(),
-							expectedParamType.getName());
-				}
-			}
-			for (String actualName : actual.keySet()) {
-				Object actualValue = actual.get(actualName);
-				Class expectedParamType = (Class) expected.get(actualName);
-				boolean paramExpected = expected.containsKey(actualName);
-				if (!paramExpected) {
-					newValidationException("param-extra", actualName, query,
-							expected.asList());
-				}
-				if (expectedParamType.isPrimitive() && actualValue == null)
-					newValidationException("param-type-null", 
-							actualName, query, expectedParamType.getName());
-				if (actualValue != null 
-				 && !Filters.wrap(expectedParamType).isInstance(actualValue)) {
-					newValidationException("param-type-mismatch",
-							actualName, query, actualValue,
-							actualValue.getClass().getName(),
-							expectedParamType.getName());
-				}
-			}
-		}
-	}
-	
-	Map<Integer, Object> removeGaps(Map<Integer, Object> map) {
-		if (map == null || !map.containsValue(GAP_FILLER))
-			return map;
-		List<Integer> gaps = new ArrayList<Integer>();
-		for (Integer key : map.keySet())
-			if (map.get(key) == GAP_FILLER)
-				gaps.add(key);
-		for (Integer gap : gaps) {
-			map.remove(gap);
-		}
-		return map;
-	}
-
-	void newValidationException(String msgKey, Object...args) {
-		throw new ArgumentException(_loc.get(msgKey, args), null, null, false);
-	}
-
 	public List getResultList() {
 		_em.assertNotCloseInvoked();
 		Object ob = execute();
@@ -457,20 +284,10 @@
 	public int executeUpdate() {
 		_em.assertNotCloseInvoked();
 		if (_query.getOperation() == QueryOperations.OP_DELETE) {
-			// handle which types of parameters we are using, if any
-			if (_positional != null)
-				return asInt(_query.deleteAll(_positional));
-			if (_named != null)
-				return asInt(_query.deleteAll(_named));
-			return asInt(_query.deleteAll());
+			return asInt(_query.deleteAll(_params));
 		}
 		if (_query.getOperation() == QueryOperations.OP_UPDATE) {
-			// handle which types of parameters we are using, if any
-			if (_positional != null)
-				return asInt(_query.updateAll(_positional));
-			if (_named != null)
-				return asInt(_query.updateAll(_named));
-			return asInt(_query.updateAll());
+			return asInt(_query.updateAll(_params));
 		}
 		throw new InvalidStateException(_loc.get("not-update-delete-query",
 				_query.getQueryString()), null, null, false);
@@ -510,6 +327,8 @@
 				if (value instanceof String)
 					value = Boolean.valueOf((String) value);
 				setSubclasses(((Boolean) value).booleanValue());
+			} else if ("InvalidateCache".equals(k)) {
+				invalidate();
 			} else if ("FilterListener".equals(k))
 				addFilterListener(Filters.hintToFilterListener(value, _query
 						.getBroker().getClassLoader()));
@@ -570,8 +389,8 @@
 		return setParameter(position, convertTemporalType(value, t));
 	}
 
-	public OpenJPAQuery setParameter(int position, Date value, TemporalType type) {
-		return setParameter(position, convertTemporalType(value, type));
+	public OpenJPAQuery setParameter(int pos, Date value, TemporalType type) {
+		return setParameter(pos, convertTemporalType(value, type));
 	}
 
 	/**
@@ -600,28 +419,10 @@
 		_em.assertNotCloseInvoked();
 		_query.lock();
 		try {
-			if (isNative() && position < 1) {
-				throw new IllegalArgumentException(_loc.get("bad-pos-params",
-						position, _query.getQueryString()).toString());
-			}
-			// not allowed to mix positional and named parameters (EDR2 3.6.4)
-			if (_named != null)
-				throw new InvalidStateException(_loc.get(
-						"no-pos-named-params-mix", _query.getQueryString()),
-						null, null, false);
-
-			if (position < 1)
-				throw new InvalidStateException(_loc.get("illegal-index",
-						position), null, null, false);
-
-			if (_positional == null)
-				_positional = new TreeMap<Integer, Object>();
-
-			_positional.put(position, value);
-			for (int i = 1; i < position; i++)
-				if (!_positional.containsKey(i))
-					_positional.put(i, GAP_FILLER);
-
+			if (_params == null)
+				_params = new ParameterMap(isNative() ? 
+					ParameterMap.Type.POSITIONAL : null);
+			_params.put(position, value);
 			return this;
 		} finally {
 			_query.unlock();
@@ -633,8 +434,8 @@
 		return setParameter(name, convertTemporalType(value, type));
 	}
 
-	public OpenJPAQuery setParameter(String name, Date value, TemporalType type) {
-		return setParameter(name, convertTemporalType(value, type));
+	public OpenJPAQuery setParameter(String name, Date value, TemporalType t) {
+		return setParameter(name, convertTemporalType(value, t));
 	}
 
 	public OpenJPAQuery setParameter(String name, Object value) {
@@ -642,19 +443,10 @@
 		_em.assertNotCloseInvoked();
 		_query.lock();
 		try {
-			if (isNative()) {
-				throw new IllegalArgumentException(_loc.get("no-named-params",
-						name, _query.getQueryString()).toString());
-			}
-			// not allowed to mix positional and named parameters (EDR2 3.6.4)
-			if (_positional != null)
-				throw new InvalidStateException(_loc.get(
-						"no-pos-named-params-mix", _query.getQueryString()),
-						null, null, false);
-
-			if (_named == null)
-				_named = new HashMap();
-			_named.put(name, value);
+			if (_params == null)
+				_params = new ParameterMap(isNative() ? 
+					ParameterMap.Type.POSITIONAL : null);
+			_params.put(name, value);
 			return this;
 		} finally {
 			_query.unlock();
@@ -664,37 +456,30 @@
 	public boolean isNative() {
 		return QueryLanguages.LANG_SQL.equals(getLanguage());
 	}
-
+	
 	public boolean hasPositionalParameters() {
-		return _positional != null;
+		return _params != null && _params.isPositional() && !_params.isEmpty();
 	}
 
-	/**
-	 * Gets the array of positional parameter values. A value of
-	 * <code>GAP_FILLER</code> indicates that user has not set the
-	 * corresponding positional parameter. A value of null implies that user has
-	 * set the value as null.
-	 */
 	public Object[] getPositionalParameters() {
 		_query.lock();
 		try {
-			return (_positional == null) ? EMPTY_ARRAY : _positional.values()
-					.toArray();
+			return hasPositionalParameters() ? _params.values().toArray()
+				: EMPTY_ARRAY;
 		} finally {
 			_query.unlock();
 		}
 	}
-
+	
 	public OpenJPAQuery setParameters(Object... params) {
 		_query.assertOpen();
 		_em.assertNotCloseInvoked();
 		_query.lock();
 		try {
-			_positional = null;
-			_named = null;
-			if (params != null)
-				for (int i = 0; i < params.length; i++)
-					setParameter(i + 1, params[i]);
+			if (params == null)
+				return this;
+			for (int i = 0; i < params.length; i++)
+			    setParameter(i + 1, params[i]);
 			return this;
 		} finally {
 			_query.unlock();
@@ -704,8 +489,8 @@
 	public Map getNamedParameters() {
 		_query.lock();
 		try {
-			return (_named == null) ? Collections.EMPTY_MAP : Collections
-					.unmodifiableMap(_named);
+			return (_params == null || !_params.isNamed())
+				? Collections.EMPTY_MAP : _params.getMap();
 		} finally {
 			_query.unlock();
 		}
@@ -716,11 +501,12 @@
 		_em.assertNotCloseInvoked();
 		_query.lock();
 		try {
-			_positional = null;
-			_named = null;
-			if (params != null)
-				for (Map.Entry e : (Set<Map.Entry>) params.entrySet())
-					setParameter((String) e.getKey(), e.getValue());
+			if (params == null)
+				return this;
+			if (_params == null)
+				_params = new ParameterMap(isNative() ? 
+					ParameterMap.Type.POSITIONAL : null);
+			_params.putAll(params);
 			return this;
 		} finally {
 			_query.unlock();
@@ -735,6 +521,77 @@
 	public String[] getDataStoreActions(Map params) {
 		return _query.getDataStoreActions(params);
 	}
+	
+	QueryImpl setId(String id) {
+		_id = id;
+		return this;
+	}
+	
+	/**
+	 * Validates internal parameters against a given expected parameter types.
+	 * 
+	 * @param expected contains expected types of parameters.
+	 * @param strict if true then also enforces that the parameter keys match.
+	 * Otherwise only the types are compared.
+	 * A more lenient strategy is required to accommodate the use case where
+	 * named parameters are set on a JPQL query but the query is executed 
+	 * directly as a cached SQL which only supports positional parameters.   
+	 */
+	void validate(LinkedMap expected, boolean strict) {
+		if (_params == null) {
+			if (expected != null && !expected.isEmpty())
+				throw new UserException(_loc.get("param-unset", expected));
+		} else {
+			_params.validate(expected, strict);
+		}
+	}
+	
+	/**
+	 * Gets the values from ParameterMap as a map with deterministic iteration
+	 * order, optionally converting a named map to a positional one.
+	 */
+	Map getParameterMap(boolean convertToPositional) {
+		if (_params == null)
+			return null;
+		if (convertToPositional && !_params.isPositional())
+			return _params.toPositional().getMap();
+		return _params.getMap();
+	}
+	
+	/**
+	 * Cache this query with its identifier as key and SQL as value if this
+	 * query is amenable to caching and has not already been cached.
+	 * 
+	 * @return non-null if this query has already been cached. null if it can 
+	 * not be cached or cached in this call.
+	 */
+	PreparedQuery cache() {
+		if (_id == null)
+			return null;
+		Map cache = _em.getConfiguration().getPreparedQueryCacheInstance();
+		if (cache == null)
+			return null;
+		PreparedQuery cached = (PreparedQuery)cache.get(_id);
+		if (cached == PreparedQuery.NOT_CACHABLE)
+			return null;
+		if (cached == null) {
+			String[] sqls = _query.getDataStoreActions(getParameterMap(true));
+			boolean cacheable = sqls.length == 1;
+			if (!cacheable) {
+				cache.put(_id, PreparedQuery.NOT_CACHABLE);
+				return null;
+			}
+			cached = new PreparedQuery(_id, sqls[0], _query); 
+			cache.put(_id, cached);
+			return null;
+		}
+		return cached;
+	}
+	
+	public boolean invalidate() {
+		Map cache = _em.getConfiguration().getPreparedQueryCacheInstance();
+		return cache != null && cache.remove(_id) != null;
+	}
 
 	public int hashCode() {
 		return _query.hashCode();