Modified: 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java
URL: 
http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java
 (original)
+++ 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java
 Sun Jun  7 01:05:22 2015
@@ -63,6 +63,8 @@ import static org.apache.openjpa.persist
 import static org.apache.openjpa.persistence.MetaDataTag.QUERY;
 import static org.apache.openjpa.persistence.MetaDataTag.READ_ONLY;
 import static org.apache.openjpa.persistence.MetaDataTag.SEQ_GENERATOR;
+import static 
org.apache.openjpa.persistence.MetaDataTag.STOREDPROCEDURE_QUERIES;
+import static org.apache.openjpa.persistence.MetaDataTag.STOREDPROCEDURE_QUERY;
 import static org.apache.openjpa.persistence.MetaDataTag.TYPE;
 import static org.apache.openjpa.persistence.MetaDataTag.VERSION;
 
@@ -120,9 +122,12 @@ import javax.persistence.NamedNativeQuer
 import javax.persistence.NamedNativeQuery;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
+import javax.persistence.NamedStoredProcedureQueries;
+import javax.persistence.NamedStoredProcedureQuery;
 import javax.persistence.OneToMany;
 import javax.persistence.OneToOne;
 import javax.persistence.OrderBy;
+import javax.persistence.ParameterMode;
 import javax.persistence.PostLoad;
 import javax.persistence.PostPersist;
 import javax.persistence.PostRemove;
@@ -132,6 +137,7 @@ import javax.persistence.PreRemove;
 import javax.persistence.PreUpdate;
 import javax.persistence.QueryHint;
 import javax.persistence.SequenceGenerator;
+import javax.persistence.StoredProcedureParameter;
 import javax.persistence.Version;
 
 import org.apache.commons.lang.StringUtils;
@@ -156,6 +162,7 @@ import org.apache.openjpa.meta.Lifecycle
 import org.apache.openjpa.meta.MetaDataFactory;
 import org.apache.openjpa.meta.MetaDataModes;
 import org.apache.openjpa.meta.MetaDataRepository;
+import org.apache.openjpa.meta.MultiQueryMetaData;
 import org.apache.openjpa.meta.Order;
 import org.apache.openjpa.meta.QueryMetaData;
 import org.apache.openjpa.meta.SequenceMetaData;
@@ -203,6 +210,8 @@ public class AnnotationPersistenceMetaDa
         _tags.put(MapsId.class, MAPPED_BY_ID);
         _tags.put(NamedNativeQueries.class, NATIVE_QUERIES);
         _tags.put(NamedNativeQuery.class, NATIVE_QUERY);
+        _tags.put(NamedStoredProcedureQueries.class, STOREDPROCEDURE_QUERIES);
+        _tags.put(NamedStoredProcedureQuery.class, STOREDPROCEDURE_QUERY);
         _tags.put(NamedQueries.class, QUERIES);
         _tags.put(NamedQuery.class, QUERY);
         _tags.put(OrderBy.class, ORDER_BY);
@@ -471,6 +480,14 @@ public class AnnotationPersistenceMetaDa
                     if (isQueryMode() && (pkgMode & MODE_QUERY) == 0)
                         parseNamedQueries(pkg, (NamedQuery) anno);
                     break;
+                case STOREDPROCEDURE_QUERIES:
+                    if (isQueryMode())
+                        parseNamedStoredProcedureQueries(pkg, 
((NamedStoredProcedureQueries) anno).value());
+                    break;
+                case STOREDPROCEDURE_QUERY:
+                    if (isQueryMode())
+                        parseNamedStoredProcedureQueries(pkg, 
((NamedStoredProcedureQuery) anno));
+                    break;
                 case SEQ_GENERATOR:
                     if (isMappingOverrideMode() &&
                         (pkgMode & MODE_MAPPING) == 0)
@@ -623,6 +640,14 @@ public class AnnotationPersistenceMetaDa
                     if (isQueryMode() && (meta.getSourceMode() & 
MODE_QUERY)==0)
                         parseNamedQueries(_cls, (NamedQuery) anno);
                     break;
+                case STOREDPROCEDURE_QUERIES:
+                    if (isQueryMode())
+                        parseNamedStoredProcedureQueries(_cls, 
((NamedStoredProcedureQueries) anno).value());
+                    break;
+                case STOREDPROCEDURE_QUERY:
+                    if (isQueryMode())
+                        parseNamedStoredProcedureQueries(_cls, 
((NamedStoredProcedureQuery) anno));
+                    break;
                 case SEQ_GENERATOR:
                     if (isMappingOverrideMode())
                         parseSequenceGenerator(_cls, (SequenceGenerator) anno);
@@ -1043,8 +1068,8 @@ public class AnnotationPersistenceMetaDa
      * If FetchGroup A includes FetchGroup B, then a bi-link is set between
      * A and B. Both A and B must be declared in the same Class.
      * <br>
-     * Call {@link #parseFetchAttribute(ClassMetaData,
-     * org.apache.openjpa.meta.FetchGroup, FetchAttribute)} only after the
+     * Call {@link #parseFetchAttribute(ClassMetaData, 
org.apache.openjpa.meta.FetchGroup, FetchAttributeImpl)}
+     * only after the
      * bi-links have been established, because a field f will not only add the
      * fetch group A which explicitly includes f to its custom fetch groups but
      * also will also add any fetch group B that includes A.
@@ -2128,5 +2153,75 @@ public class AnnotationPersistenceMetaDa
     protected String normalizeCatalogName(String catName) {
         return catName;
     }
+
+
+    protected MultiQueryMetaData.Parameter.Mode 
toKernelParameterMode(ParameterMode mode) {
+        switch (mode) {
+            case IN : return MultiQueryMetaData.Parameter.Mode.IN;
+            case OUT: return MultiQueryMetaData.Parameter.Mode.OUT;
+            case INOUT: return MultiQueryMetaData.Parameter.Mode.INOUT;
+            case REF_CURSOR: return MultiQueryMetaData.Parameter.Mode.CURSOR;
+            default : return MultiQueryMetaData.Parameter.Mode.IN;
+        }
+    }
+
+    protected void addSourceInfo(AnnotatedElement el, QueryMetaData meta) {
+        meta.setSource(getSourceFile(), (el instanceof Class) ? el : null,
+                SourceTracker.SRC_ANNOTATIONS, getSourceFile() == null ? "" : 
getSourceFile().getPath());
+        if (isMetaDataMode())
+            meta.setSourceMode(MODE_META);
+        else if (isMappingMode())
+            meta.setSourceMode(MODE_MAPPING);
+        else
+            meta.setSourceMode(MODE_QUERY);
+    }
+
+    protected void addHints(QueryMetaData meta, QueryHint...hints) {
+        for (QueryHint hint : hints)
+            meta.addHint(hint.name(), hint.value());
+
+    }
+
+    private void parseNamedStoredProcedureQueries(AnnotatedElement el, 
NamedStoredProcedureQuery... procs) {
+        for (NamedStoredProcedureQuery proc : procs) {
+            if (StringUtils.isEmpty(proc.name()))
+                throw new MetaDataException(_loc.get("stored-proc-no-name", 
el));
+            if (StringUtils.isEmpty(proc.procedureName()))
+                throw new MetaDataException(_loc.get("stored-proc-no-dbname", 
el));
+
+            // Query metadata name
+            MultiQueryMetaData meta = new MultiQueryMetaData(_cls, 
proc.name(), proc.procedureName(), false);
+            QueryMetaData existing = getRepository().addQueryMetaData(meta);
+            if (existing != null && existing.getDefiningType() != 
meta.getDefiningType()) {
+                getLog().warn(_loc.get("dup-query", meta.getName(), el, 
existing.getDefiningType()));
+            }
+
+            // Important: The query string is the name of the database stored 
procedure
+            meta.setQueryString(proc.procedureName());
+
+            // For each mapping name/result class, add a component metadata
+            // The spec restricts that either ResultMappingName or 
ResultClasses be specified, but not both.
+            // This is relevant because the order of mapping must match the 
order in which the
+            // components are returned
+            Class<?>[] resultClasses = proc.resultClasses();
+            String[] resultSetMappings = proc.resultSetMappings();
+            if (resultClasses.length > 0 && resultSetMappings.length > 0)
+                throw new 
MetaDataException(_loc.get("stored-proc-both-mapping", el));
+            for (Class<?> res : resultClasses) {
+                meta.addComponent(res);
+            }
+            for (String mapping : resultSetMappings) {
+                meta.addComponent(mapping);
+            }
+            StoredProcedureParameter[] params = proc.parameters();
+            for (StoredProcedureParameter param : params) {
+                MultiQueryMetaData.Parameter p = new 
MultiQueryMetaData.Parameter(
+                        param.name(), param.type(), 
toKernelParameterMode(param.mode()));
+                meta.registerParameter(p);
+            }
+            addHints(meta, proc.hints());
+            addSourceInfo(el, meta);
+        }
+    }
 }
 

Modified: 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
URL: 
http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
 (original)
+++ 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
 Sun Jun  7 01:05:22 2015
@@ -42,6 +42,7 @@ import org.apache.openjpa.lib.log.Log;
 import org.apache.openjpa.lib.util.Closeable;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.meta.MetaDataRepository;
+import org.apache.openjpa.meta.QueryMetaData;
 import org.apache.openjpa.persistence.criteria.CriteriaBuilderImpl;
 import org.apache.openjpa.persistence.criteria.OpenJPACriteriaBuilder;
 import org.apache.openjpa.persistence.meta.MetamodelImpl;
@@ -364,7 +365,11 @@ public class EntityManagerFactoryImpl
 
     @Override
     public void addNamedQuery(String name, Query query) {
-        throw new UnsupportedOperationException("JPA 2.1");
+        org.apache.openjpa.kernel.Query kernelQuery = 
((QueryImpl<?>)query).getDelegate();
+        MetaDataRepository metaDataRepositoryInstance = 
_factory.getConfiguration().getMetaDataRepositoryInstance();
+        QueryMetaData metaData = 
metaDataRepositoryInstance.newQueryMetaData(null, null);
+        metaData.setFrom(kernelQuery);
+        metaDataRepositoryInstance.addQueryMetaData(metaData);
     }
 
     @Override

Modified: 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
URL: 
http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
 (original)
+++ 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
 Sun Jun  7 01:05:22 2015
@@ -83,6 +83,8 @@ import org.apache.openjpa.lib.util.Close
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.MetaDataRepository;
+import org.apache.openjpa.meta.MultiQueryMetaData;
 import org.apache.openjpa.meta.QueryMetaData;
 import org.apache.openjpa.meta.SequenceMetaData;
 import org.apache.openjpa.persistence.criteria.CriteriaBuilderImpl;
@@ -119,7 +121,8 @@ public class EntityManagerImpl
     private Map<FetchConfiguration,FetchPlan> _plans = new 
IdentityHashMap<FetchConfiguration,FetchPlan>(1);
     protected RuntimeExceptionTranslator _ret = 
PersistenceExceptions.getRollbackTranslator(this);
     private boolean _convertPositionalParams = false;
-    
+    private boolean _isJoinedToTransaction;
+
     public EntityManagerImpl() {
         // for Externalizable
     }
@@ -559,6 +562,13 @@ public class EntityManagerImpl
     }
 
     public void joinTransaction() {
+        if (!_broker.syncWithManagedTransaction()) {
+            throw new TransactionRequiredException(_loc.get
+                    ("no-managed-trans"), null, null, false);
+        } else {
+            _isJoinedToTransaction = true;
+        }
+
         assertNotCloseInvoked();
         if (!_broker.syncWithManagedTransaction())
             throw new TransactionRequiredException(_loc.get
@@ -567,8 +577,7 @@ public class EntityManagerImpl
 
     @Override
     public boolean isJoinedToTransaction() {
-        // throw new UnsupportedOperationException("JPA 2.1");
-        return false;
+        return isActive() && _isJoinedToTransaction;
     }
 
     public void begin() {
@@ -1079,22 +1088,60 @@ public class EntityManagerImpl
 
     @Override
     public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
-        throw new UnsupportedOperationException("JPA 2.1");
+        QueryMetaData meta = getQueryMetadata(name);
+        if (!MultiQueryMetaData.class.isInstance(meta)) {
+            throw new RuntimeException(name + " is not an identifier for a 
Stored Procedure Query");
+        }
+        return newProcedure(((MultiQueryMetaData)meta).getProcedureName(), 
(MultiQueryMetaData)meta);
     }
 
     @Override
     public StoredProcedureQuery createStoredProcedureQuery(String 
procedureName) {
-        throw new UnsupportedOperationException("JPA 2.1");
+        return newProcedure(procedureName, null);
     }
 
     @Override
     public StoredProcedureQuery createStoredProcedureQuery(String 
procedureName, Class... resultClasses) {
-        throw new UnsupportedOperationException("JPA 2.1");
+        String tempName = "StoredProcedure-"+System.nanoTime();
+        MultiQueryMetaData meta = new MultiQueryMetaData(null, tempName, 
procedureName, true);
+        for (Class<?> res : resultClasses) {
+            meta.addComponent(res);
+        }
+        return newProcedure(procedureName, meta);
     }
 
     @Override
     public StoredProcedureQuery createStoredProcedureQuery(String 
procedureName, String... resultSetMappings) {
-        throw new UnsupportedOperationException("JPA 2.1");
+        String tempName = "StoredProcedure-"+System.nanoTime();
+        MultiQueryMetaData meta = new MultiQueryMetaData(null, tempName, 
procedureName, true);
+        for (String mapping : resultSetMappings) {
+            meta.addComponent(mapping);
+        }
+        return newProcedure(procedureName, meta);
+    }
+
+    /**
+     * Creates a query to execute a Stored Procedure.
+     * <br>
+     * Construction of a {@link StoredProcedureQuery} object is a three step 
process
+     * <LI>
+     * <LI>a {@link org.apache.openjpa.kernel.Query kernel query} {@code kQ} 
is created for
+     * {@link QueryLanguages#LANG_SQL SQL} language with the string {@code S}
+     * <LI>a {@link QueryImpl facade query} {@code fQ} is created that 
delegates to the kernel query {@code kQ}
+     * <LI>a {@link StoredProcedureQueryImpl stored procedure query} is 
created that delegates to the facade query
+     * {@code fQ}.
+     * <br>
+     *
+     */
+    private StoredProcedureQuery newProcedure(String procedureName, 
MultiQueryMetaData meta) {
+        org.apache.openjpa.kernel.QueryImpl kernelQuery = 
(org.apache.openjpa.kernel.QueryImpl)
+                _broker.newQuery(QueryLanguages.LANG_STORED_PROC, 
procedureName);
+        kernelQuery.getStoreQuery().setQuery(meta);
+        if (meta != null) {
+            
getConfiguration().getMetaDataRepositoryInstance().addQueryMetaData(meta);
+            kernelQuery.setResultMapping(null, meta.getResultSetMappingName());
+        }
+        return new StoredProcedureQueryImpl(procedureName, meta, new 
QueryImpl(this, _ret, kernelQuery, meta));
     }
 
     protected <T> QueryImpl<T> newQueryImpl(org.apache.openjpa.kernel.Query 
kernelQuery, QueryMetaData qmd) {
@@ -1942,4 +1989,13 @@ public class EntityManagerImpl
         }
         return properties;
     }
+
+    private QueryMetaData getQueryMetadata(String name) {
+        MetaDataRepository repos = 
_broker.getConfiguration().getMetaDataRepositoryInstance();
+        QueryMetaData meta = repos.getQueryMetaData(null, name, 
_broker.getClassLoader(), true);
+        if (meta == null) {
+            throw new RuntimeException("No query named [" + name + "]");
+        }
+        return meta;
+    }
 }

Modified: 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java
URL: 
http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java
 (original)
+++ 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java
 Sun Jun  7 01:05:22 2015
@@ -88,5 +88,8 @@ public enum MetaDataTag {
     READ_ONLY,
     TYPE,
     REPLICATED,
-    OPENJPA_VERSION
+    OPENJPA_VERSION,
+    // JPA 2.1
+    STOREDPROCEDURE_QUERIES,
+    STOREDPROCEDURE_QUERY
 }

Modified: 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java
URL: 
http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java
 (original)
+++ 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java
 Sun Jun  7 01:05:22 2015
@@ -20,6 +20,7 @@ package org.apache.openjpa.persistence;
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.annotation.Annotation;
 import java.net.URL;
 import java.security.AccessController;
 import java.util.ArrayList;
@@ -39,6 +40,8 @@ import javax.persistence.NamedNativeQuer
 import javax.persistence.NamedNativeQuery;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
+import javax.persistence.NamedStoredProcedureQueries;
+import javax.persistence.NamedStoredProcedureQuery;
 import javax.persistence.SqlResultSetMapping;
 import javax.persistence.SqlResultSetMappings;
 import javax.persistence.metamodel.StaticMetamodel;
@@ -371,10 +374,20 @@ public class PersistenceMetaDataFactory
                 hasNamedNativeQuery(queryName, ((NamedNativeQueries) cls.
                     getAnnotation(NamedNativeQueries.class)).value()))
                 return cls;
+            if (isAnnotated(cls, NamedStoredProcedureQuery.class)
+                    && hasNamedStoredProcedure(queryName, 
cls.getAnnotation(NamedStoredProcedureQuery.class)))
+                return cls;
+            if (isAnnotated(cls, NamedStoredProcedureQueries.class)
+                    && hasNamedStoredProcedure(queryName, 
cls.getAnnotation(NamedStoredProcedureQueries.class).value()))
+                return cls;
         }
         return null;
     }
 
+    private boolean isAnnotated(Class<?> cls, Class<? extends Annotation> 
annotationClazz) {
+        return 
AccessController.doPrivileged(J2DoPrivHelper.isAnnotationPresentAction(cls, 
annotationClazz));
+    }
+
     @Override
     public Class<?> getResultSetMappingScope(String rsMappingName,
         ClassLoader loader) {
@@ -416,6 +429,14 @@ public class PersistenceMetaDataFactory
                 return true;
         }
         return false;
+    }
+
+    private boolean hasNamedStoredProcedure(String query, 
NamedStoredProcedureQuery... queries) {
+        for (NamedStoredProcedureQuery q : queries) {
+            if (query.equals(q.name()))
+                return true;
+        }
+        return false;
     }
 
     private boolean hasNamedNativeQuery(String query,

Added: 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java
URL: 
http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java?rev=1683972&view=auto
==============================================================================
--- 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java
 (added)
+++ 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java
 Sun Jun  7 01:05:22 2015
@@ -0,0 +1,415 @@
+/*
+ * 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.DelegatingResultList;
+import org.apache.openjpa.kernel.QueryResultCallback;
+import org.apache.openjpa.lib.rop.ResultList;
+import org.apache.openjpa.lib.rop.ResultObjectProvider;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.meta.MultiQueryMetaData;
+import org.apache.openjpa.util.RuntimeExceptionTranslator;
+import org.apache.openjpa.util.UserException;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.persistence.*;
+import javax.persistence.NoResultException;
+import javax.persistence.NonUniqueResultException;
+
+/**
+ * Implements Store Procedure based query for JPA facade.
+ * <br>
+ * A {@link StoredProcedureQuery stored procedure query} differs from other 
query types because it may return
+ * more than one result set, apart from an optional update count, whereas the 
traditional query processing in OpenJPA
+ * via the abstractions of {@link ResultObjectProvider} and {@link 
org.apache.openjpa.jdbc.sql.Result}
+ * assumed that a query will return its
+ * result in a single list.
+ * <br>
+ * This query resorts to a callback mechanism, where the execution of the 
query returns not a result, but a
+ * {@link QueryResultCallback callback object} that can be used to callback to 
OpenJPA kernel to get a series of
+ * results via the traditional result processing pathway.
+ *
+ * @author Pinaki Poddar
+ * @author Romain Manni-Bucau
+ */
+// TODO: add lock
+public class StoredProcedureQueryImpl implements StoredProcedureQuery {
+    private static final Localizer _loc = 
Localizer.forPackage(QueryImpl.class);
+
+    private final String _name;
+    private final QueryImpl<?> _delegate;
+    private final MultiQueryMetaData _meta;
+    private QueryResultCallback _callback;
+    private boolean _declaredParams; // mainly a flag for now (null or not)
+
+    /**
+     * Construct a query for executing a Stored Procedure.
+     *  @param procedureName name of the database stored procedure.
+     * @param meta
+     * @param delegate      the delegate which manages bind parameters on 
behalf of this
+     */
+    public StoredProcedureQueryImpl(String procedureName, MultiQueryMetaData 
meta, QueryImpl<?> delegate) {
+        _name = procedureName;
+        if (!isValidProcedureName(procedureName)) {
+            throw new RuntimeException(procedureName + " is not a valid 
procedure name");
+        }
+        _meta = meta;
+        _delegate = delegate;
+        _delegate.compile();
+    }
+
+    /**
+     * Gets the facade delegate that manages bind parameters on behalf of this 
receiver.
+     *
+     * @return
+     */
+    public OpenJPAQuery<?> getDelegate() {
+        return _delegate;
+    }
+
+    /**
+     * Gets the kernel delegate that is handles actual execution on behalf of 
this receiver.
+     *
+     * @return
+     */
+    public org.apache.openjpa.kernel.Query getExecutableQuery() {
+        return _delegate.getDelegate();
+    }
+
+    private void buildParametersIfNeeded() {
+        if (!_declaredParams) {
+            for (MultiQueryMetaData.Parameter entry : _meta.getParameters()) {
+                final Object key;
+                final Parameter<?> param;
+                if (entry.getName() == null) {
+                    key = entry.getPosition();
+                    param = new ParameterImpl(entry.getPosition(), 
entry.getType());
+                } else {
+                    key = entry.getName();
+                    param = new ParameterImpl(entry.getName(), 
entry.getType());
+                }
+                _delegate.declareParameter(key, param);
+            }
+            _declaredParams = true;
+        }
+    }
+
+    /**
+     * Executes this receiver by delegation to the underlying executable query.
+     * <br>
+     * This method is multi-call safe. The underlying executable query is 
executed
+     * <em>only</em> for the first invocation. Subsequent
+     */
+    @Override
+    public boolean execute() {
+        if (_callback == null) {
+            _callback = (QueryResultCallback) 
getExecutableQuery().execute(_delegate.getParameterValues());
+        }
+        return _callback.getExecutionResult();
+    }
+
+    @Override
+    public List getResultList() {
+        execute();
+        try {
+            Object list = _callback.callback();
+            RuntimeExceptionTranslator trans = PersistenceExceptions
+                    .getRollbackTranslator(_delegate.getEntityManager());
+            return new DelegatingResultList((ResultList) list, trans);
+        } catch (Exception ex) {
+            throw new javax.persistence.PersistenceException(ex);
+        }
+    }
+
+    @Override
+    public Object getSingleResult() {
+        execute();
+        try {
+            ResultList result = (ResultList) _callback.callback();
+            if (result == null || result.isEmpty())
+                throw new NoResultException(_loc.get("no-result", _name)
+                        .getMessage());
+            if (result.size() > 1)
+                throw new 
NonUniqueResultException(_loc.get("non-unique-result",
+                        _name, result.size()).getMessage());
+            RuntimeExceptionTranslator trans = PersistenceExceptions
+                    .getRollbackTranslator(_delegate.getEntityManager());
+            return new DelegatingResultList(result, trans).iterator().next();
+        } catch (Exception ex) {
+            throw new javax.persistence.PersistenceException(ex);
+        }
+    }
+
+    @Override
+    public boolean hasMoreResults() {
+        return _callback != null && _callback.hasMoreResults();
+    }
+
+    @Override
+    public int getUpdateCount() {
+        assertExecuted();
+        return _callback.getUpdateCount();
+    }
+
+    @Override
+    public int executeUpdate() {
+        execute();
+        return _callback.getUpdateCount();
+    }
+
+    @Override
+    public <T> Parameter<T> getParameter(String name, Class<T> type) {
+        // TODO JPA 2.1 Method
+        return _delegate.getParameter(name, type);
+    }
+
+    @Override
+    public <T> Parameter<T> getParameter(int position, Class<T> type) {
+        // TODO JPA 2.1 Method
+        return _delegate.getParameter(position, type);
+    }
+
+    @Override
+    public boolean isBound(Parameter<?> param) {
+        // TODO JPA 2.1 Method
+        return _delegate.isBound(param);
+    }
+
+    @Override
+    public <T> T getParameterValue(Parameter<T> param) {
+        // TODO JPA 2.1 Method
+        return _delegate.getParameterValue(param);
+    }
+
+    @Override
+    public <T> T unwrap(Class<T> cls) {
+        // TODO JPA 2.1 Method
+        return _delegate.unwrap(cls);
+    }
+
+    @Override
+    public <T> StoredProcedureQuery setParameter(Parameter<T> param, T value) {
+        buildParametersIfNeeded();
+        _delegate.setParameter(param, value);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery setParameter(Parameter<Calendar> param, 
Calendar cal, TemporalType temporalType) {
+        buildParametersIfNeeded();
+        _delegate.setParameter(param, cal, temporalType);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery setParameter(Parameter<Date> param, Date 
value, TemporalType temporalType) {
+        buildParametersIfNeeded();
+        _delegate.setParameter(param, value, temporalType);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery registerStoredProcedureParameter(int position, 
Class type, ParameterMode mode) {
+        buildParametersIfNeeded();
+        ParameterImpl param = new ParameterImpl(position, type);
+        _delegate.declareParameter(position, param);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery registerStoredProcedureParameter(String name, 
Class type, ParameterMode mode) {
+        buildParametersIfNeeded();
+        ParameterImpl param = new ParameterImpl(name, type);
+        _delegate.declareParameter(name, param);
+        return this;
+    }
+
+    @Override
+    public Object getOutputParameterValue(int position) {
+        return _callback == null ? null : _callback.getOut(position);
+    }
+
+    @Override
+    public Object getOutputParameterValue(String parameterName) {
+        return _callback == null ? null : _callback.getOut(parameterName);
+    }
+
+    @Override
+    public javax.persistence.Query setMaxResults(int maxResult) {
+        // TODO JPA 2.1 Method
+        return _delegate.setMaxResults(maxResult);
+    }
+
+    @Override
+    public int getMaxResults() {
+        // TODO JPA 2.1 Method
+        return _delegate.getMaxResults();
+    }
+
+    @Override
+    public javax.persistence.Query setFirstResult(int startPosition) {
+        // TODO JPA 2.1 Method
+        return _delegate.setFirstResult(startPosition);
+    }
+
+    @Override
+    public int getFirstResult() {
+        // TODO JPA 2.1 Method
+        return _delegate.getFirstResult();
+    }
+
+    @Override
+    public Map<String, Object> getHints() {
+        // TODO JPA 2.1 Method
+        return _delegate.getHints();
+    }
+
+    @Override
+    public Set<Parameter<?>> getParameters() {
+        buildParametersIfNeeded();
+        return _delegate.getParameters();
+    }
+
+    @Override
+    public Parameter<?> getParameter(String name) {
+        buildParametersIfNeeded();
+        return _delegate.getParameter(name);
+    }
+
+    @Override
+    public Parameter<?> getParameter(int position) {
+        buildParametersIfNeeded();
+        return _delegate.getParameter(position);
+    }
+
+    @Override
+    public Object getParameterValue(String name) {
+        buildParametersIfNeeded();
+        return _delegate.getParameterValue(name);
+    }
+
+    @Override
+    public Object getParameterValue(int position) {
+        buildParametersIfNeeded();
+        return _delegate.getParameter(position);
+    }
+
+    @Override
+    public FlushModeType getFlushMode() {
+        // TODO JPA 2.1 Method
+        return _delegate.getFlushMode();
+    }
+
+    @Override
+    public javax.persistence.Query setLockMode(LockModeType lockMode) {
+        // TODO JPA 2.1 Method
+        return _delegate.setLockMode(lockMode);
+    }
+
+    @Override
+    public LockModeType getLockMode() {
+        // TODO JPA 2.1 Method
+        return _delegate.getLockMode();
+    }
+
+    @Override
+    public StoredProcedureQuery setHint(String hintName, Object value) {
+        _delegate.setHint(hintName, value);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery setParameter(String name, Object value) {
+        buildParametersIfNeeded();
+        _delegate.setParameter(name, value);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery setParameter(String name, Calendar cal, 
TemporalType temporalType) {
+        buildParametersIfNeeded();
+        _delegate.setParameter(name, cal, temporalType);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery setParameter(String name, Date date, 
TemporalType temporalType) {
+        buildParametersIfNeeded();
+        _delegate.setParameter(name, date, temporalType);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery setParameter(int position, Object value) {
+        buildParametersIfNeeded();
+        _delegate.setParameter(position, value);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery setParameter(int position, Calendar value, 
TemporalType temporalType) {
+        buildParametersIfNeeded();
+        _delegate.setParameter(position, value, temporalType);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery setParameter(int position, Date value, 
TemporalType temporalType) {
+        buildParametersIfNeeded();
+        _delegate.setParameter(position, value, temporalType);
+        return this;
+    }
+
+    @Override
+    public StoredProcedureQuery setFlushMode(FlushModeType flushMode) {
+        // TODO JPA 2.1 Method
+        _delegate.setFlushMode(flushMode);
+        return this;
+    }
+
+    /**
+     * Asserts that user has executed this query.
+     */
+    void assertExecuted() {
+        if (_callback == null) {
+            throw new UserException(this + " has not been executed");
+        }
+    }
+
+    boolean isValidProcedureName(String s) {
+        if (s == null || s.trim().length() == 0) {
+            return false;
+        }
+        for (int i = 0; i < s.length(); i++) {
+            char ch = s.charAt(i);
+            if (ch == '#' || ch == '$' || Character.isJavaIdentifierPart(ch))
+                continue;
+            return false;
+        }
+        return true;
+    }
+
+    public String toString() {
+        return _name;
+    }
+}

Modified: 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
URL: 
http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
 (original)
+++ 
openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java
 Sun Jun  7 01:05:22 2015
@@ -601,7 +601,7 @@ public class XMLPersistenceMetaDataParse
     @Override
     protected boolean startSystemElement(String name, Attributes attrs)
         throws SAXException {
-        Object tag = (Object) _elems.get(name);
+        Object tag = _elems.get(name);
         boolean ret = false;
         if (tag == null) {
             if (isMappingOverrideMode())


Reply via email to