diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java index 62a5734e63a..6f6fd9219de 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java @@ -29,9 +29,9 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.instrument.classloading.LoadTimeWeaver; import org.springframework.jdbc.datasource.lookup.SingleDataSourceLookup; import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager; -import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo; import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager; import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor; +import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo; import org.springframework.util.ClassUtils; /** @@ -195,8 +195,8 @@ public class LocalContainerEntityManagerFactoryBean extends AbstractEntityManage this.persistenceUnitInfo = determinePersistenceUnitInfo(managerToUse); JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter(); - if (jpaVendorAdapter != null && this.persistenceUnitInfo instanceof MutablePersistenceUnitInfo) { - ((MutablePersistenceUnitInfo) this.persistenceUnitInfo).setPersistenceProviderPackageName( + if (jpaVendorAdapter != null && this.persistenceUnitInfo instanceof SmartPersistenceUnitInfo) { + ((SmartPersistenceUnitInfo) this.persistenceUnitInfo).setPersistenceProviderPackageName( jpaVendorAdapter.getPersistenceProviderRootPackage()); } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java index 25b5a7f1e07..cc5db6c1b90 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,14 @@ package org.springframework.orm.jpa.persistenceunit; import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; - import javax.persistence.PersistenceException; import javax.persistence.spi.PersistenceUnitInfo; import javax.sql.DataSource; @@ -40,6 +42,7 @@ import org.springframework.instrument.classloading.LoadTimeWeaver; import org.springframework.jdbc.datasource.lookup.DataSourceLookup; import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; import org.springframework.jdbc.datasource.lookup.MapDataSourceLookup; +import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; /** @@ -78,7 +81,8 @@ public class DefaultPersistenceUnitManager public final static String ORIGINAL_DEFAULT_PERSISTENCE_UNIT_ROOT_LOCATION = "classpath:"; - /** Location of persistence.xml file(s) */ + private static final boolean jpa2ApiPresent = ClassUtils.hasMethod(PersistenceUnitInfo.class, "getSharedCacheMode"); + private String[] persistenceXmlLocations = new String[] {DEFAULT_PERSISTENCE_XML_LOCATION}; private String defaultPersistenceUnitRootLocation = ORIGINAL_DEFAULT_PERSISTENCE_UNIT_ROOT_LOCATION; @@ -95,8 +99,7 @@ public class DefaultPersistenceUnitManager private final Set persistenceUnitInfoNames = new HashSet(); - private final Map persistenceUnitInfos = - new HashMap(); + private final Map persistenceUnitInfos = new HashMap(); /** @@ -273,8 +276,7 @@ public class DefaultPersistenceUnitManager this.persistenceUnitInfoNames.clear(); this.persistenceUnitInfos.clear(); SpringPersistenceUnitInfo[] puis = readPersistenceUnitInfos(); - for (int i = 0; i < puis.length; i++) { - SpringPersistenceUnitInfo pui = puis[i]; + for (SpringPersistenceUnitInfo pui : puis) { if (pui.getPersistenceUnitRootUrl() == null) { pui.setPersistenceUnitRootUrl(determineDefaultPersistenceUnitRootUrl()); } @@ -290,7 +292,12 @@ public class DefaultPersistenceUnitManager postProcessPersistenceUnitInfo(pui); String name = pui.getPersistenceUnitName(); this.persistenceUnitInfoNames.add(name); - this.persistenceUnitInfos.put(name, pui); + PersistenceUnitInfo puiToStore = pui; + if (jpa2ApiPresent) { + puiToStore = (PersistenceUnitInfo) Proxy.newProxyInstance(SmartPersistenceUnitInfo.class.getClassLoader(), + new Class[] {SmartPersistenceUnitInfo.class}, new Jpa2PersistenceUnitInfoDecorator(pui)); + } + this.persistenceUnitInfos.put(name, puiToStore); } } @@ -331,7 +338,7 @@ public class DefaultPersistenceUnitManager * @param persistenceUnitName the name of the desired persistence unit * @return the PersistenceUnitInfo in mutable form, or null if not available */ - protected final MutablePersistenceUnitInfo getPersistenceUnitInfo(String persistenceUnitName) { + protected final PersistenceUnitInfo getPersistenceUnitInfo(String persistenceUnitName) { return this.persistenceUnitInfos.get(persistenceUnitName); } @@ -387,4 +394,45 @@ public class DefaultPersistenceUnitManager return pui; } + + /** + * Decorator that exposes a JPA 2.0 compliant PersistenceUnitInfo interface for a + * JPA 1.0 based SpringPersistenceUnitInfo object, adapting the getSharedCacheMode + * and getValidationMode methods from String names to enum return values. + */ + private static class Jpa2PersistenceUnitInfoDecorator implements InvocationHandler { + + private final SpringPersistenceUnitInfo target; + + private final Class sharedCacheModeEnum; + + private final Class validationModeEnum; + + @SuppressWarnings("unchecked") + public Jpa2PersistenceUnitInfoDecorator(SpringPersistenceUnitInfo target) { + this.target = target; + try { + this.sharedCacheModeEnum = (Class) + ClassUtils.forName("javax.persistence.SharedCacheMode", PersistenceUnitInfo.class.getClassLoader()); + this.validationModeEnum = (Class) + ClassUtils.forName("javax.persistence.ValidationMode", PersistenceUnitInfo.class.getClassLoader()); + } + catch (Exception ex) { + throw new IllegalStateException("JPA 2.0 API enum types not present", ex); + } + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.getName().equals("getSharedCacheMode")) { + return Enum.valueOf(this.sharedCacheModeEnum, this.target.getSharedCacheModeName()); + } + else if (method.getName().equals("getValidationMode")) { + return Enum.valueOf(this.validationModeEnum, this.target.getValidationModeName()); + } + else { + return method.invoke(this.target, args); + } + } + } + } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java index 3aea7f374b2..dd2da772a92 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,9 +20,7 @@ import java.net.URL; import java.util.LinkedList; import java.util.List; import java.util.Properties; - import javax.persistence.spi.ClassTransformer; -import javax.persistence.spi.PersistenceUnitInfo; import javax.persistence.spi.PersistenceUnitTransactionType; import javax.sql.DataSource; @@ -41,7 +39,7 @@ import org.springframework.util.ClassUtils; * @author Costin Leau * @since 2.0 */ -public class MutablePersistenceUnitInfo implements PersistenceUnitInfo { +public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo { private String persistenceUnitName; @@ -65,6 +63,8 @@ public class MutablePersistenceUnitInfo implements PersistenceUnitInfo { private Properties properties = new Properties(); + private String persistenceXMLSchemaVersion = "1.0"; + private String persistenceProviderPackageName; @@ -169,6 +169,14 @@ public class MutablePersistenceUnitInfo implements PersistenceUnitInfo { return this.properties; } + public void setPersistenceXMLSchemaVersion(String persistenceXMLSchemaVersion) { + this.persistenceXMLSchemaVersion = persistenceXMLSchemaVersion; + } + + public String getPersistenceXMLSchemaVersion() { + return this.persistenceXMLSchemaVersion; + } + public void setPersistenceProviderPackageName(String persistenceProviderPackageName) { this.persistenceProviderPackageName = persistenceProviderPackageName; } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java index 7e90deb49e3..d69a05b3ae8 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,6 +52,10 @@ import org.springframework.util.xml.SimpleSaxErrorHandler; */ class PersistenceUnitReader { + private static final String PERSISTENCE_UNIT = "persistence-unit"; + + private static final String UNIT_NAME = "name"; + private static final String MAPPING_FILE_NAME = "mapping-file"; private static final String JAR_FILE_URL = "jar-file"; @@ -62,17 +66,17 @@ class PersistenceUnitReader { private static final String PROVIDER = "provider"; - private static final String EXCLUDE_UNLISTED_CLASSES = "exclude-unlisted-classes"; + private static final String TRANSACTION_TYPE = "transaction-type"; - private static final String NON_JTA_DATA_SOURCE = "non-jta-data-source"; + private static final String SHARED_CACHE_MODE = "shared-cache-mode"; + + private static final String VALIDATION_MODE = "validation-mode"; private static final String JTA_DATA_SOURCE = "jta-data-source"; - private static final String TRANSACTION_TYPE = "transaction-type"; + private static final String NON_JTA_DATA_SOURCE = "non-jta-data-source"; - private static final String PERSISTENCE_UNIT = "persistence-unit"; - - private static final String UNIT_NAME = "name"; + private static final String EXCLUDE_UNLISTED_CLASSES = "exclude-unlisted-classes"; private static final String META_INF = "META-INF"; @@ -274,6 +278,18 @@ class PersistenceUnitReader { unitInfo.setTransactionType(PersistenceUnitTransactionType.valueOf(txType)); } + // set JPA 2.0 shared cache mode + String cacheMode = persistenceUnit.getAttribute(SHARED_CACHE_MODE).trim(); + if (StringUtils.hasText(cacheMode)) { + unitInfo.setSharedCacheModeName(cacheMode); + } + + // set JPA 2.0 validation mode + String validationMode = persistenceUnit.getAttribute(VALIDATION_MODE).trim(); + if (StringUtils.hasText(validationMode)) { + unitInfo.setValidationModeName(validationMode); + } + // data-source String jtaDataSource = DomUtils.getChildElementValueByTagName(persistenceUnit, JTA_DATA_SOURCE); if (StringUtils.hasText(jtaDataSource)) { diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SmartPersistenceUnitInfo.java b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SmartPersistenceUnitInfo.java new file mode 100644 index 00000000000..176e49556f4 --- /dev/null +++ b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SmartPersistenceUnitInfo.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed 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.springframework.orm.jpa.persistenceunit; + +import javax.persistence.spi.PersistenceUnitInfo; + +/** + * Extension of the standard JPA PersistenceUnitInfo interface, for advanced collaboration + * between Spring's {@link org.springframework.orm.jpa.LocalEntityManagerFactoryBean} and + * {@link PersistenceUnitManager} implementations. + * + * @author Juergen Hoeller + * @since 3.0.1 + * @see PersistenceUnitManager + * @see org.springframework.orm.jpa.LocalEntityManagerFactoryBean + */ +public interface SmartPersistenceUnitInfo extends PersistenceUnitInfo { + + /** + * Set the persistence provider's own package name, for exclusion from class transformation. + * @see #addTransformer(javax.persistence.spi.ClassTransformer) + * @see #getNewTempClassLoader() + */ + void setPersistenceProviderPackageName(String persistenceProviderPackageName); + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java index 9abce3c5c43..6d7e94956fd 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import org.springframework.core.DecoratingClassLoader; import org.springframework.instrument.classloading.LoadTimeWeaver; import org.springframework.instrument.classloading.SimpleThrowawayClassLoader; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * Subclass of {@link MutablePersistenceUnitInfo} that adds instrumentation hooks based on @@ -37,11 +38,39 @@ import org.springframework.util.Assert; */ class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo { + private static final String DEFAULT_SHARED_CACHE_MODE_NAME = "UNSPECIFIED"; + + private static final String DEFAULT_VALIDATION_MODE_NAME = "AUTO"; + + + private String sharedCacheModeName = DEFAULT_SHARED_CACHE_MODE_NAME; + + private String validationModeName = DEFAULT_VALIDATION_MODE_NAME; + private LoadTimeWeaver loadTimeWeaver; private ClassLoader classLoader; + public void setSharedCacheModeName(String sharedCacheModeName) { + this.sharedCacheModeName = + (StringUtils.hasLength(sharedCacheModeName) ? sharedCacheModeName : DEFAULT_SHARED_CACHE_MODE_NAME); + } + + public String getSharedCacheModeName() { + return this.sharedCacheModeName; + } + + public void setValidationModeName(String validationModeName) { + this.validationModeName = + (StringUtils.hasLength(validationModeName) ? validationModeName : DEFAULT_VALIDATION_MODE_NAME); + } + + public String getValidationModeName() { + return this.validationModeName; + } + + /** * Initialize this PersistenceUnitInfo with the LoadTimeWeaver SPI interface * used by Spring to add instrumentation to the current class loader.