Modified: openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java?rev=1480473&r1=1480472&r2=1480473&view=diff ============================================================================== --- openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java (original) +++ openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java Wed May 8 21:38:29 2013 @@ -94,6 +94,9 @@ import javax.persistence.AccessType; import javax.persistence.Basic; import javax.persistence.Cacheable; import javax.persistence.CascadeType; +import javax.persistence.Convert; +import javax.persistence.Converter; +import javax.persistence.Converts; import javax.persistence.ElementCollection; import javax.persistence.Embeddable; import javax.persistence.Embedded; @@ -120,9 +123,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; @@ -159,6 +165,7 @@ import org.apache.openjpa.meta.MetaDataR import org.apache.openjpa.meta.Order; import org.apache.openjpa.meta.QueryMetaData; import org.apache.openjpa.meta.SequenceMetaData; +import org.apache.openjpa.meta.MultiQueryMetaData; import org.apache.openjpa.meta.UpdateStrategies; import org.apache.openjpa.meta.ValueMetaData; import org.apache.openjpa.meta.ValueStrategies; @@ -181,7 +188,7 @@ import serp.util.Strings; public class AnnotationPersistenceMetaDataParser implements MetaDataModes { - private static final Localizer _loc = Localizer.forPackage + protected static final Localizer _loc = Localizer.forPackage (AnnotationPersistenceMetaDataParser.class); private static final Map<Class<?>, MetaDataTag> _tags = @@ -189,12 +196,14 @@ public class AnnotationPersistenceMetaDa static { _tags.put(Access.class, ACCESS); + _tags.put(Convert.class, MetaDataTag.CONVERT); + _tags.put(Converter.class, MetaDataTag.CONVERTER); + _tags.put(Converts.class, MetaDataTag.CONVERTS); _tags.put(Cacheable.class, CACHEABLE); _tags.put(EmbeddedId.class, EMBEDDED_ID); _tags.put(EntityListeners.class, ENTITY_LISTENERS); _tags.put(ExcludeDefaultListeners.class, EXCLUDE_DEFAULT_LISTENERS); - _tags.put(ExcludeSuperclassListeners.class, - EXCLUDE_SUPERCLASS_LISTENERS); + _tags.put(ExcludeSuperclassListeners.class, EXCLUDE_SUPERCLASS_LISTENERS); _tags.put(FlushModeType.class, FLUSH_MODE); _tags.put(GeneratedValue.class, GENERATED_VALUE); _tags.put(Id.class, ID); @@ -239,7 +248,7 @@ public class AnnotationPersistenceMetaDa private final OpenJPAConfiguration _conf; private final Log _log; - private MetaDataRepository _repos = null; + protected MetaDataRepository _repos = null; private ClassLoader _envLoader = null; private boolean _override = false; private int _mode = MODE_NONE; @@ -448,6 +457,8 @@ public class AnnotationPersistenceMetaDa MetaDataTag tag; for (Annotation anno : pkg.getDeclaredAnnotations()) { + System.err.println("parsePackageAnnotations( " + _cls.getName() + ") : " + + anno.annotationType().getClass().getSimpleName()); tag = _tags.get(anno.annotationType()); if (tag == null) { handleUnknownPackageAnnotation(pkg, anno); @@ -457,13 +468,13 @@ public class AnnotationPersistenceMetaDa switch (tag) { case NATIVE_QUERIES: if (isQueryMode() && (pkgMode & MODE_QUERY) == 0) - parseNamedNativeQueries(pkg, - ((NamedNativeQueries) anno).value()); + parseNamedNativeQueries(pkg, ((NamedNativeQueries) anno).value()); break; case NATIVE_QUERY: if (isQueryMode() && (pkgMode & MODE_QUERY) == 0) parseNamedNativeQueries(pkg, (NamedNativeQuery) anno); break; + case QUERIES: if (isQueryMode() && (pkgMode & MODE_QUERY) == 0) parseNamedQueries(pkg, ((NamedQueries) anno).value()); @@ -572,6 +583,8 @@ public class AnnotationPersistenceMetaDa Collection<LifecycleCallbacks>[] listeners = null; MetaDataTag tag; for (Annotation anno : _cls.getDeclaredAnnotations()) { + System.err.println("parseClassAnnotations( " + _cls.getName() + ") : " + + anno.annotationType().getSimpleName()); tag = _tags.get(anno.annotationType()); if (tag == null) { handleUnknownClassAnnotation(meta, anno); @@ -604,8 +617,7 @@ public class AnnotationPersistenceMetaDa break; case NATIVE_QUERIES: if (isQueryMode() && (meta.getSourceMode() & MODE_QUERY)==0) - parseNamedNativeQueries(_cls, - ((NamedNativeQueries) anno).value()); + parseNamedNativeQueries(_cls, ((NamedNativeQueries) anno).value()); break; case NATIVE_QUERY: if (isQueryMode() && (meta.getSourceMode() & MODE_QUERY)==0) @@ -1844,28 +1856,18 @@ public class AnnotationPersistenceMetaDa * Parse @NamedQuery. */ private void parseNamedQueries(AnnotatedElement el, NamedQuery... queries) { - QueryMetaData meta; for (NamedQuery query : queries) { if (StringUtils.isEmpty(query.name())) throw new MetaDataException(_loc.get("no-query-name", el)); if (StringUtils.isEmpty(query.query())) - throw new MetaDataException(_loc.get("no-query-string", - query.name(), el)); + throw new MetaDataException(_loc.get("no-query-string", query.name(), el)); if (_log.isTraceEnabled()) _log.trace(_loc.get("parse-query", query.name())); - meta = getRepository().searchQueryMetaDataByName(query.name()); - if (meta != null) { - Class<?> definingType = meta.getDefiningType(); - if ((definingType == null || definingType != _cls) - && _log.isWarnEnabled()) { - _log.warn(_loc.get("dup-query", query.name(), el, - definingType)); - } - continue; - } - meta = getRepository().addQueryMetaData(_cls, query.name()); + QueryMetaData meta = new QueryMetaData(_cls, query.name()); + addQueryMetaData(el, meta); + meta.setLanguage(JPQLParser.LANG_JPQL); meta.setQueryString(query.query()); for (QueryHint hint : query.hints()) @@ -1885,6 +1887,20 @@ public class AnnotationPersistenceMetaDa meta.setSourceMode(MODE_QUERY); } } + + /** + * Adds the given query meta. + * @param meta a query meta data + * @exception throws exception if a query meta data with the same name of the given meta + * already exists in the repository. + */ + protected void addQueryMetaData(Object location, QueryMetaData meta) { + QueryMetaData existing = getRepository().addQueryMetaData(meta); + if (existing != null) { + Class<?> scope = existing.getDefiningType(); + throw new UserException(_loc.get("dup-query", meta.getName(), location, scope)); + } + } /** * A private worker method that calculates the lock mode for an individual NamedQuery. If the NamedQuery is @@ -1912,33 +1928,48 @@ public class AnnotationPersistenceMetaDa return lmt; } + 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()); + + } /** * Parse @NamedNativeQuery. */ - private void parseNamedNativeQueries(AnnotatedElement el, - NamedNativeQuery... queries) { - QueryMetaData meta; + private void parseNamedNativeQueries(AnnotatedElement el, NamedNativeQuery... queries) { for (NamedNativeQuery query : queries) { if (StringUtils.isEmpty(query.name())) - throw new MetaDataException(_loc.get("no-native-query-name", - el)); + throw new MetaDataException(_loc.get("no-native-query-name", el)); if (StringUtils.isEmpty(query.query())) - throw new MetaDataException(_loc.get("no-native-query-string", - query.name(), el)); + throw new MetaDataException(_loc.get("no-native-query-string", query.name(), el)); if (_log.isTraceEnabled()) _log.trace(_loc.get("parse-native-query", query.name())); - meta = getRepository().searchQueryMetaDataByName(query.name()); - if (meta != null) { - Class<?> defType = meta.getDefiningType(); - if ((defType != _cls) && _log.isWarnEnabled()) { - _log.warn(_loc.get("dup-query", query.name(), el, defType)); - } - continue; - } - - meta = getRepository().addQueryMetaData(null, query.name()); + QueryMetaData meta = new QueryMetaData(_cls, query.name()); + addQueryMetaData(el, meta); + meta.setLanguage(QueryLanguages.LANG_SQL); meta.setQueryString(query.query()); Class<?> res = query.resultClass(); @@ -1949,17 +1980,8 @@ public class AnnotationPersistenceMetaDa if (!StringUtils.isEmpty(query.resultSetMapping())) meta.setResultSetMappingName(query.resultSetMapping()); - for (QueryHint hint : query.hints()) - meta.addHint(hint.name(), hint.value()); - - 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); + addHints(meta, query.hints()); + addSourceInfo(el, meta); } }
Modified: openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java?rev=1480473&r1=1480472&r2=1480473&view=diff ============================================================================== --- openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java (original) +++ openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java Wed May 8 21:38:29 2013 @@ -47,6 +47,7 @@ import org.apache.openjpa.lib.conf.Value 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.QueryMetaData; import org.apache.openjpa.persistence.criteria.CriteriaBuilderImpl; import org.apache.openjpa.persistence.criteria.OpenJPACriteriaBuilder; import org.apache.openjpa.persistence.meta.MetamodelImpl; @@ -417,9 +418,8 @@ public class EntityManagerFactoryImpl @Override public void addNamedQuery(String name, Query query) { org.apache.openjpa.kernel.Query kernelQuery = ((QueryImpl<?>)query).getDelegate(); - - _factory.getConfiguration().getMetaDataRepositoryInstance() - .addQueryMetaData(name, kernelQuery); + QueryMetaData meta = new QueryMetaData(name, kernelQuery); + _factory.getConfiguration().getMetaDataRepositoryInstance().addQueryMetaData(meta); } Modified: openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java?rev=1480473&r1=1480472&r2=1480473&view=diff ============================================================================== --- openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java (original) +++ openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java Wed May 8 21:38:29 2013 @@ -46,8 +46,10 @@ import javax.persistence.EntityGraph; import javax.persistence.EntityManager; import javax.persistence.FlushModeType; import javax.persistence.LockModeType; +import javax.persistence.NamedStoredProcedureQuery; import javax.persistence.PessimisticLockScope; import javax.persistence.Query; +import javax.persistence.SqlResultSetMapping; import javax.persistence.StoredProcedureQuery; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaDelete; @@ -83,8 +85,10 @@ 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.QueryMetaData; import org.apache.openjpa.meta.SequenceMetaData; +import org.apache.openjpa.meta.MultiQueryMetaData; import org.apache.openjpa.persistence.criteria.CriteriaBuilderImpl; import org.apache.openjpa.persistence.criteria.CriteriaDeleteImpl; import org.apache.openjpa.persistence.criteria.CriteriaUpdateImpl; @@ -122,6 +126,7 @@ 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 = false; private transient Log _log; public EntityManagerImpl() { @@ -564,11 +569,18 @@ public class EntityManagerImpl return this; } + /** + * Joins a transaction, if availble. + */ public void joinTransaction() { assertNotCloseInvoked(); - if (!_broker.syncWithManagedTransaction()) + + if (!_broker.syncWithManagedTransaction()) { throw new TransactionRequiredException(_loc.get ("no-managed-trans"), null, null, false); + } else { + _isJoinedToTransaction = true; + } } public void begin() { @@ -1032,8 +1044,7 @@ public class EntityManagerImpl _broker.assertOpen(); try { QueryMetaData meta = _broker.getConfiguration(). - getMetaDataRepositoryInstance().getQueryMetaData(null, name, - _broker.getClassLoader(), true); + getMetaDataRepositoryInstance().getQueryMetaData(null, name, _broker.getClassLoader(), true); String qid = meta.getQueryString(); PreparedQuery pq = JPQLParser.LANG_JPQL.equals(meta.getLanguage()) ? getPreparedQuery(qid) : null; @@ -1059,26 +1070,57 @@ public class EntityManagerImpl } } + /** + * Creates a SQL query from the given string. + * + * @param sql can be a proper SQL statement, or simply a stored procedure name + */ public OpenJPAQuery createNativeQuery(String query) { validateSQL(query); return createQuery(QueryLanguages.LANG_SQL, query); } + /** + * Creates a SQL query from the given string. + * + * @param sql can be a proper SQL statement, or simply a stored procedure name + * @param cls the type of expected result. + */ public OpenJPAQuery createNativeQuery(String query, Class cls) { return createNativeQuery(query).setResultClass(cls); } + /** + * Creates a SQL query from the given string. + * + * @param sql can be a proper SQL statement, or simply a stored procedure name + * @param mappingName name of the mapping used to convert the results into memory + */ public OpenJPAQuery createNativeQuery(String query, String mappingName) { assertNotCloseInvoked(); validateSQL(query); - org.apache.openjpa.kernel.Query kernelQuery = _broker.newQuery( - QueryLanguages.LANG_SQL, query); + org.apache.openjpa.kernel.Query kernelQuery = _broker.newQuery(QueryLanguages.LANG_SQL, query); kernelQuery.setResultMapping(null, mappingName); return newQueryImpl(kernelQuery, null, _log); } - protected <T> QueryImpl<T> newQueryImpl(org.apache.openjpa.kernel.Query kernelQuery, - QueryMetaData qmd, Log log) { + /** + * Creates a facade version of a query from the given kerenl query and metadata. + * @param <T> type of expected result + * @param kernelQuery + * @param qmd + * @param log supply a logger + * @return + */ + protected <T> QueryImpl<T> newQueryImpl(org.apache.openjpa.kernel.Query kernelQuery, QueryMetaData qmd, Log log) { + return new QueryImpl<T>(this, _ret, kernelQuery, qmd, log); + } + + /** + * Same as {@linkplain #newQueryImpl(org.apache.openjpa.kernel.Query, QueryMetaData, Log)}} except + * a default logger is supplied. + */ + protected <T> QueryImpl<T> newQueryImpl(org.apache.openjpa.kernel.Query kernelQuery, QueryMetaData qmd) { return new QueryImpl<T>(this, _ret, kernelQuery, qmd, _log); } @@ -1090,11 +1132,11 @@ public class EntityManagerImpl * query creation */ protected <T> QueryImpl<T> newQueryImpl(org.apache.openjpa.kernel.Query kernelQuery) { - return new QueryImpl<T>(this, _ret, kernelQuery, null); + return new QueryImpl<T>(this, _ret, kernelQuery, _log); } /** - * Validate that the user provided SQL. + * Validate that the user provided SQL or simply a name of a stored procedure. */ protected void validateSQL(String query) { if (StringUtils.trimToNull(query) == null) @@ -1925,34 +1967,108 @@ public class EntityManagerImpl return facadeQuery; } + /** + * Creates a Query that can be executed as a Stored Procedure. + * <br> + * The details about the Stored Procedure is specified in a {@link NamedStoredProcedureQuery} annotation + * or its equivalent XML descriptor. The input argument is the name attribute of that annotation. + * <br> + * Construction of a {@link StoredProcedureQuery} object is a three step process + * <LI>a corresponding SQL {@code S} (e.g. {@code "call <procedure>(?,?...)"}) is formed. + * The number of parameter argument in the {@coe call} statement + * is deternmined by the parameters declared in {@link NamedStoredProcedureQuery#parameters()} annotation. + * <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> + * A {@link NamedStoredProcedureQuery named Stored Procedure Query} also may specify how its results be mapped. + * A {@link QueryResultMapping query result mapping} is implicitly associated. It is implicit as opposed to + * other {@link QueryResultMapping} mapping instances that are created via {@link SqlResultSetMapping} + * annotation which has an explicit name. The name of the implicit mapping is always + * {@code <name>.ResultSetMapping}. + * + */ @Override public StoredProcedureQuery createNamedStoredProcedureQuery(String name) { // TODO JPA 2.1 Method - return null; + QueryMetaData meta = getQueryMetadata(name); + if (meta instanceof MultiQueryMetaData) { + throw new RuntimeException(name + " is not a Stored Procedure Query"); + } + String procedureName = meta.getQueryString(); + int parameterCount = ((MultiQueryMetaData)meta).getParameterCount(); + StringBuilder sql = new StringBuilder("call ").append(procedureName).append("("); + for (int i = 0; i < parameterCount; i++) { + sql.append("?"); + if (i < parameterCount-1) sql.append(","); + } + sql.append(")"); + return sp(sql.toString(), (MultiQueryMetaData)meta, name + ".ResultSetMapping"); +// org.apache.openjpa.kernel.Query kernelQuery = _broker.newQuery(QueryLanguages.LANG_SQL, sql.toString()); +// kernelQuery.setResultMapping(null, name + ".ResultSetMapping"); +// org.apache.openjpa.persistence.QueryImpl<?> facadeQuery = new QueryImpl(this, _ret, kernelQuery, meta, _log); +// +// return new StoredProcedureQueryImpl(facadeQuery); } + /** + * Creates a Stored Procedure Query directly from the name of the database procedure. + * This method follows three similiar steps as in {@link #createNamedStoredProcedureQuery(String)} + * but with some critical difference. + * <br>The major difference in this case from creating a query by its logical name is lack of metadata + * at the time of creation. It is not known at this point how many arguments are required by the + * procedure or how its results be mapped. + * <br> + * <LI>So the name of the procedure itself is treated as a query string (which is not a valid SQL}. + * <LI>No result set mapping name is associated with the kernel query. + * + */ @Override public StoredProcedureQuery createStoredProcedureQuery(String procedureName) { // TODO JPA 2.1 Method - return null; + + org.apache.openjpa.kernel.Query kernelQuery = _broker.newQuery(QueryLanguages.LANG_STORED_PROC, + procedureName); + org.apache.openjpa.persistence.QueryImpl<?> facadeQuery = new QueryImpl(this, _ret, + kernelQuery, null, _log); + return new StoredProcedureQueryImpl(procedureName, facadeQuery); } @Override public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) { // TODO JPA 2.1 Method - return null; + String tempName = "Temp"+System.currentTimeMillis(); + MultiQueryMetaData meta = new MultiQueryMetaData(null, "xyz"); + for (Class res : resultClasses) { + meta.addComponent().setResultType(res); + } + return sp(procedureName, meta, tempName); } @Override public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) { // TODO JPA 2.1 Method - return null; + String tempName = "Temp"+System.currentTimeMillis(); + MultiQueryMetaData meta = new MultiQueryMetaData(null, "xyz"); + for (String mapping : resultSetMappings) { + meta.addComponent().setResultSetMappingName(mapping); + } + return sp(procedureName, meta, tempName); + } + + private StoredProcedureQuery sp(String sql, MultiQueryMetaData meta, String mappingName) { + org.apache.openjpa.kernel.Query kernelQuery = _broker.newQuery(QueryLanguages.LANG_STORED_PROC, sql); + kernelQuery.setResultMapping(null, mappingName); + org.apache.openjpa.persistence.QueryImpl<?> facadeQuery = new QueryImpl(this, _ret, kernelQuery, meta, _log); + return new StoredProcedureQueryImpl(sql, facadeQuery); } @Override public boolean isJoinedToTransaction() { // TODO JPA 2.1 Method - return false; + return isActive() && _isJoinedToTransaction; } @Override @@ -1978,4 +2094,20 @@ public class EntityManagerImpl // TODO JPA 2.1 Method return null; } + + /** + * Gets the metadat associated with the given name. + * @param name logical name in which a query has been registered. + * @return the metadata associated with the named query + * @throws UserException if no query has been registered with the given name. + */ + 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 stored procedure query named [" + name + "]"); + } + return meta; + } + } Modified: openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java?rev=1480473&r1=1480472&r2=1480473&view=diff ============================================================================== --- openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java (original) +++ openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java Wed May 8 21:38:29 2013 @@ -21,6 +21,7 @@ package org.apache.openjpa.persistence; import java.util.Collection; import java.util.Map; +import javax.persistence.EntityGraph; import javax.persistence.LockModeType; import javax.persistence.PessimisticLockScope; Modified: openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java?rev=1480473&r1=1480472&r2=1480473&view=diff ============================================================================== --- openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java (original) +++ openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java Wed May 8 21:38:29 2013 @@ -30,6 +30,10 @@ package org.apache.openjpa.persistence; * @nojavadoc */ public enum MetaDataTag { + // Position for these need to be determined + CONVERTER, + CONVERT, + CONVERTS, // sorted by XML order ACCESS, CACHEABLE, Modified: openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java?rev=1480473&r1=1480472&r2=1480473&view=diff ============================================================================== --- openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java (original) +++ openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java Wed May 8 21:38:29 2013 @@ -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; @@ -349,32 +352,37 @@ public class PersistenceMetaDataFactory return null; Collection<Class<?>> classes = repos.loadPersistentTypes(false, loader); for (Class<?> cls : classes) { - if ((AccessController.doPrivileged(J2DoPrivHelper - .isAnnotationPresentAction(cls, NamedQuery.class))) - .booleanValue() && hasNamedQuery - (queryName, (NamedQuery) cls.getAnnotation(NamedQuery.class))) + if (isAnnotated(cls, NamedQuery.class) + && hasNamedQuery(queryName, cls.getAnnotation(NamedQuery.class))) return cls; - if ((AccessController.doPrivileged(J2DoPrivHelper - .isAnnotationPresentAction(cls, NamedQueries.class))) - .booleanValue() && - hasNamedQuery(queryName, ((NamedQueries) cls. - getAnnotation(NamedQueries.class)).value())) + if (isAnnotated(cls, NamedQueries.class) + && hasNamedQuery(queryName, cls.getAnnotation(NamedQueries.class).value())) return cls; - if ((AccessController.doPrivileged(J2DoPrivHelper - .isAnnotationPresentAction(cls, NamedNativeQuery.class))) - .booleanValue() && - hasNamedNativeQuery(queryName, (NamedNativeQuery) cls. - getAnnotation(NamedNativeQuery.class))) + if (isAnnotated(cls, NamedNativeQuery.class) + && hasNamedNativeQuery(queryName, cls.getAnnotation(NamedNativeQuery.class))) return cls; - if ((AccessController.doPrivileged(J2DoPrivHelper - .isAnnotationPresentAction(cls, NamedNativeQueries.class))) - .booleanValue() && - hasNamedNativeQuery(queryName, ((NamedNativeQueries) cls. - getAnnotation(NamedNativeQueries.class)).value())) + if (isAnnotated(cls, NamedNativeQueries.class) + && hasNamedNativeQuery(queryName, 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; } + + /** + * Affirms if the given class is annotated with the given annotation. + * @param cls + * @param annotationClazz + * @return + */ + private boolean isAnnotated(Class<?> cls, Class<? extends Annotation> annotationClazz) { + return AccessController.doPrivileged(J2DoPrivHelper.isAnnotationPresentAction(cls, annotationClazz)); + } @Override public Class<?> getResultSetMappingScope(String rsMappingName, @@ -427,6 +435,15 @@ public class PersistenceMetaDataFactory } return false; } + + private boolean hasNamedStoredProcedure(String query, NamedStoredProcedureQuery... queries) { + for (NamedStoredProcedureQuery q : queries) { + if (query.equals(q.name())) + return true; + } + return false; + } + @Override protected MetaDataFilter newMetaDataFilter() { Added: openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java?rev=1480473&view=auto ============================================================================== --- openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java (added) +++ openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java Wed May 8 21:38:29 2013 @@ -0,0 +1,342 @@ +/* + * 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.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.persistence.FlushModeType; +import javax.persistence.LockModeType; +import javax.persistence.Parameter; +import javax.persistence.ParameterMode; +import javax.persistence.StoredProcedureQuery; +import javax.persistence.TemporalType; + +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.util.RuntimeExceptionTranslator; +import org.apache.openjpa.util.UserException; + +/** + * 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 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 + * + */ +public class StoredProcedureQueryImpl<X> implements StoredProcedureQuery { + final String _name; + final AbstractQuery<?> _delegate; + QueryResultCallback _callback; + + public StoredProcedureQueryImpl(String name, AbstractQuery<?> delegate) { + _name = name; + _delegate = delegate; + _delegate.compile(); + } + + public OpenJPAQuery<?> getDelegate() { + return _delegate; + } + + @Override + public boolean execute() { + if (_callback == null) { + _callback = (QueryResultCallback)((QueryImpl<?>)_delegate).getDelegate() + .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 RuntimeException(ex); + } + } + + @Override + public Object getSingleResult() { + // TODO JPA 2.1 Method + return _delegate.getSingleResult(); + } + + @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) { + // TODO JPA 2.1 Method + _delegate.setParameter(param, value); + return this; + } + + @Override + public StoredProcedureQuery setParameter(Parameter<Calendar> param, Calendar cal, TemporalType temporalType) { + // TODO JPA 2.1 Method + _delegate.setParameter(param, cal, temporalType); + return this; + } + + @Override + public StoredProcedureQuery setParameter(Parameter<Date> param, Date value, TemporalType temporalType) { + // TODO JPA 2.1 Method + _delegate.setParameter(param, value, temporalType); + return this; + } + + @Override + public StoredProcedureQuery registerStoredProcedureParameter(int position, Class type, ParameterMode mode) { + // TODO JPA 2.1 Method + ParameterImpl param = new ParameterImpl(position, type); + _delegate.declareParameter(position, param); + return this; + } + + @Override + public StoredProcedureQuery registerStoredProcedureParameter(String name, Class type, ParameterMode mode) { + // TODO JPA 2.1 Method + ParameterImpl param = new ParameterImpl(name, type); + _delegate.declareParameter(name, param); + return this; + } + + @Override + public Object getOutputParameterValue(int position) { + // TODO JPA 2.1 Method + return _delegate.getParameterValue(position); + } + + @Override + public Object getOutputParameterValue(String parameterName) { + // TODO JPA 2.1 Method + return _delegate.getParameterValue(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() { + // TODO JPA 2.1 Method + return _delegate.getParameters(); + } + + @Override + public Parameter<?> getParameter(String name) { + // TODO JPA 2.1 Method + return _delegate.getParameter(name); + } + + @Override + public Parameter<?> getParameter(int position) { + // TODO JPA 2.1 Method + return _delegate.getParameter(position); + } + + @Override + public Object getParameterValue(String name) { + // TODO JPA 2.1 Method + return _delegate.getParameterValue(name); + } + + @Override + public Object getParameterValue(int position) { + // TODO JPA 2.1 Method + 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) { + // TODO JPA 2.1 Method + _delegate.setHint(hintName, value); + return this; + } + + @Override + public StoredProcedureQuery setParameter(String name, Object value) { + // TODO JPA 2.1 Method + _delegate.setParameter(name, value); + return this; + } + + @Override + public StoredProcedureQuery setParameter(String name, Calendar cal, TemporalType temporalType) { + // TODO JPA 2.1 Method + _delegate.setParameter(name, cal, temporalType); + return this; + } + + @Override + public StoredProcedureQuery setParameter(String name, Date date, TemporalType temporalType) { + // TODO JPA 2.1 Method + _delegate.setParameter(name, date, temporalType); + return this; + } + + @Override + public StoredProcedureQuery setParameter(int position, Object value) { + // TODO JPA 2.1 Method + _delegate.setParameter(position, value); + return this; + } + + @Override + public StoredProcedureQuery setParameter(int position, Calendar value, TemporalType temporalType) { + // TODO JPA 2.1 Method + _delegate.setParameter(position, value, temporalType); + return this; + } + + @Override + public StoredProcedureQuery setParameter(int position, Date value, TemporalType temporalType) { + // TODO JPA 2.1 Method + _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"); + } + } + + public String toString() { + return _name; + } + +} Propchange: openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java?rev=1480473&r1=1480472&r2=1480473&view=diff ============================================================================== --- openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java (original) +++ openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java Wed May 8 21:38:29 2013 @@ -79,6 +79,7 @@ import static org.apache.openjpa.persist import org.apache.openjpa.util.ImplHelper; import org.apache.openjpa.util.InternalException; import org.apache.openjpa.util.MetaDataException; +import org.apache.openjpa.util.UserException; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; @@ -121,8 +122,7 @@ public class XMLPersistenceMetaDataParse SEQUENCE_GEN_SCHEMA } - private static final Map<String, Object> _elems = - new HashMap<String, Object>(); + private static final Map<String, Object> _elems = new HashMap<String, Object>(); // Map for storing deferred metadata which needs to be populated // after embeddables are loaded. @@ -1830,19 +1830,8 @@ public class XMLPersistenceMetaDataParse if (log.isTraceEnabled()) log.trace(_loc.get("parse-query", name)); - QueryMetaData meta = getRepository().searchQueryMetaDataByName(name); - if (meta != null) { - Class<?> defType = meta.getDefiningType(); - if ((defType != _cls) && log.isWarnEnabled()) { - log.warn(_loc.get("dup-query", name, currentLocation(), - defType)); - } - pushElement(meta); - return true; - } + QueryMetaData meta = new QueryMetaData(_cls, name); - meta = getRepository().addQueryMetaData(null, name); - meta.setDefiningType(_cls); meta.setLanguage(JPQLParser.LANG_JPQL); meta.setQueryString(attrs.getValue("query")); String lockModeStr = attrs.getValue("lock-mode"); @@ -1865,11 +1854,28 @@ public class XMLPersistenceMetaDataParse meta.setSourceMode(MODE_MAPPING); else meta.setSourceMode(MODE_QUERY); + + addQueryMetaData(cur, meta); pushElement(meta); return true; } /** + * Adds the given query meta. + * @param meta a query meta data + * @exception throws exception if a query meta data with the same name of the given meta + * already exists in the repository. + */ + protected void addQueryMetaData(Object location, QueryMetaData meta) { + QueryMetaData existing = getRepository().addQueryMetaData(meta); + if (existing != null) { + Class<?> scope = existing.getDefiningType(); + throw new UserException(_loc.get("dup-query", meta.getName(), location, scope)); + } + } + + + /** * A private worker method that calculates the lock mode for an individual NamedQuery. If the NamedQuery is * configured to use the NONE lock mode(explicit or implicit), this method will promote the lock to a READ * level lock. This was done to allow for JPA1 apps to function properly under a 2.0 runtime. @@ -1945,8 +1951,8 @@ public class XMLPersistenceMetaDataParse log.warn(_loc.get("override-query", name, currentLocation())); } - meta = getRepository().addQueryMetaData(null, name); - meta.setDefiningType(_cls); + meta = new QueryMetaData(_cls, name); + getRepository().addQueryMetaData(meta); meta.setLanguage(QueryLanguages.LANG_SQL); meta.setQueryString(attrs.getValue("query")); String val = attrs.getValue("result-class");
