001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.persistence;
017:
018: import org.apache.openejb.util.Join;
019:
020: import java.lang.instrument.ClassFileTransformer;
021: import java.lang.instrument.IllegalClassFormatException;
022: import java.net.MalformedURLException;
023: import java.net.URL;
024: import java.net.URI;
025: import java.net.URISyntaxException;
026: import java.net.URLDecoder;
027: import java.net.URLEncoder;
028: import java.security.ProtectionDomain;
029: import java.util.ArrayList;
030: import java.util.List;
031: import java.util.Properties;
032: import java.io.File;
033: import java.io.IOException;
034: import javax.persistence.spi.ClassTransformer;
035: import javax.persistence.spi.PersistenceUnitInfo;
036: import javax.persistence.spi.PersistenceUnitTransactionType;
037: import javax.sql.DataSource;
038:
039: public class PersistenceUnitInfoImpl implements PersistenceUnitInfo {
040: /**
041: * External handler which handles adding a runtime ClassTransformer to the classloader.
042: */
043: private final PersistenceClassLoaderHandler persistenceClassLoaderHandler;
044:
045: /**
046: * The unique id of this persistence unit.
047: */
048: private String id;
049:
050: /**
051: * Name of this persistence unit. The JPA specification has restrictions on the
052: * uniqueness of this name.
053: */
054: private String persistenceUnitName;
055:
056: /**
057: * Name of the persistence provider implementation class.
058: */
059: private String persistenceProviderClassName;
060:
061: /**
062: * Does this persistence unti participate in JTA transactions or does it manage
063: * resource local tranactions using the JDBC APIs.
064: */
065: private PersistenceUnitTransactionType transactionType = PersistenceUnitTransactionType.JTA;
066:
067: /**
068: * Data source used by jta persistence units for accessing transactional data.
069: */
070: private DataSource jtaDataSource;
071:
072: /**
073: * Data source used by non-jta persistence units and by jta persistence units for
074: * non-transactional operations such as accessing a primary key table or sequence.
075: */
076: private DataSource nonJtaDataSource;
077:
078: /**
079: * Names if the entity-mapping.xml files relative to to the persistenceUnitRootUrl.
080: */
081: private final List<String> mappingFileNames = new ArrayList<String>();
082:
083: /**
084: * The jar file locations that make up this persistence unit.
085: */
086: private final List<URL> jarFileUrls = new ArrayList<URL>();
087:
088: /**
089: * Location of the root of the persistent unit. The directory in which
090: * META-INF/persistence.xml is located.
091: */
092: private URL persistenceUnitRootUrl;
093:
094: /**
095: * List of the managed entity classes.
096: */
097: private final List<String> managedClassNames = new ArrayList<String>();
098:
099: /**
100: * Should class not listed in the persistence unit be managed by the EntityManager?
101: */
102: private boolean excludeUnlistedClasses;
103:
104: /**
105: * JPA provider properties for this persistence unit.
106: */
107: private Properties properties;
108:
109: /**
110: * Class loader used by JPA to load Entity classes.
111: */
112: private ClassLoader classLoader;
113:
114: public PersistenceUnitInfoImpl() {
115: this .persistenceClassLoaderHandler = null;
116: }
117:
118: public PersistenceUnitInfoImpl(
119: PersistenceClassLoaderHandler persistenceClassLoaderHandler) {
120: this .persistenceClassLoaderHandler = persistenceClassLoaderHandler;
121: }
122:
123: public String getId() {
124: return id;
125: }
126:
127: public void setId(String id) {
128: this .id = id;
129: }
130:
131: public String getPersistenceUnitName() {
132: return persistenceUnitName;
133: }
134:
135: public void setPersistenceUnitName(String persistenceUnitName) {
136: this .persistenceUnitName = persistenceUnitName;
137: }
138:
139: public String getPersistenceProviderClassName() {
140: return persistenceProviderClassName;
141: }
142:
143: public void setPersistenceProviderClassName(
144: String persistenceProviderClassName) {
145: this .persistenceProviderClassName = persistenceProviderClassName;
146: }
147:
148: public PersistenceUnitTransactionType getTransactionType() {
149: return transactionType;
150: }
151:
152: public void setTransactionType(
153: PersistenceUnitTransactionType transactionType) {
154: this .transactionType = transactionType;
155: }
156:
157: public DataSource getJtaDataSource() {
158: return jtaDataSource;
159: }
160:
161: public void setJtaDataSource(DataSource jtaDataSource) {
162: this .jtaDataSource = jtaDataSource;
163: }
164:
165: public DataSource getNonJtaDataSource() {
166: return nonJtaDataSource;
167: }
168:
169: public void setNonJtaDataSource(DataSource nonJtaDataSource) {
170: this .nonJtaDataSource = nonJtaDataSource;
171: }
172:
173: public List<String> getMappingFileNames() {
174: return mappingFileNames;
175: }
176:
177: public void setMappingFileNames(List<String> mappingFileNames) {
178: if (mappingFileNames == null) {
179: throw new NullPointerException("mappingFileNames is null");
180: }
181: this .mappingFileNames.clear();
182: this .mappingFileNames.addAll(mappingFileNames);
183: }
184:
185: public void addMappingFileName(String mappingFileName) {
186: if (mappingFileName == null) {
187: throw new NullPointerException("mappingFileName is null");
188: }
189: mappingFileNames.add(mappingFileName);
190: }
191:
192: public List<URL> getJarFileUrls() {
193: return jarFileUrls;
194: }
195:
196: public URL getPersistenceUnitRootUrl() {
197: return persistenceUnitRootUrl;
198: }
199:
200: public void setRootUrlAndJarUrls(String persistenceUnitRootUrl,
201: List<String> jarFiles) throws MalformedURLException {
202: File root = new File(persistenceUnitRootUrl);
203:
204: this .persistenceUnitRootUrl = toUrl(root);
205: try {
206:
207: for (String path : jarFiles) {
208: File file = new File(root, path);
209: file = file.getCanonicalFile();
210: jarFileUrls.add(toUrl(file));
211: }
212: } catch (IOException e) {
213: throw new IllegalStateException(e);
214: }
215: }
216:
217: private URL toUrl(File root) throws MalformedURLException {
218: URL url = root.toURL();
219:
220: try {
221: url.toURI();
222: } catch (URISyntaxException e) {
223: // Likely has spaces in it.
224: try {
225: String s = url.toExternalForm();
226: URL fixed = new URL(s.replaceAll(" ", "%20"));
227: fixed.toURI();
228: url = fixed;
229: } catch (MalformedURLException e1) {
230: } catch (URISyntaxException e1) {
231: // oh well, we tried.
232: }
233: }
234:
235: return url;
236: }
237:
238: public List<String> getManagedClassNames() {
239: return managedClassNames;
240: }
241:
242: public void setManagedClassNames(List<String> managedClassNames) {
243: if (managedClassNames == null) {
244: throw new NullPointerException("managedClassNames is null");
245: }
246: this .managedClassNames.clear();
247: this .managedClassNames.addAll(managedClassNames);
248: }
249:
250: public void addManagedClassName(String className) {
251: managedClassNames.add(className);
252: }
253:
254: public boolean excludeUnlistedClasses() {
255: return excludeUnlistedClasses;
256: }
257:
258: public void setExcludeUnlistedClasses(boolean excludeUnlistedClasses) {
259: this .excludeUnlistedClasses = excludeUnlistedClasses;
260: }
261:
262: public Properties getProperties() {
263: return properties;
264: }
265:
266: public void setProperties(Properties properties) {
267: this .properties = properties;
268: }
269:
270: public ClassLoader getClassLoader() {
271: return classLoader;
272: }
273:
274: public void setClassLoader(ClassLoader classLoader) {
275: this .classLoader = classLoader;
276: }
277:
278: public void addTransformer(ClassTransformer classTransformer) {
279: if (persistenceClassLoaderHandler != null) {
280: PersistenceClassFileTransformer classFileTransformer = new PersistenceClassFileTransformer(
281: classTransformer);
282: persistenceClassLoaderHandler.addTransformer(id,
283: classLoader, classFileTransformer);
284: }
285: }
286:
287: public ClassLoader getNewTempClassLoader() {
288: if (persistenceClassLoaderHandler != null) {
289: return persistenceClassLoaderHandler
290: .getNewTempClassLoader(classLoader);
291: } else {
292: return null;
293: }
294: }
295:
296: public static class PersistenceClassFileTransformer implements
297: ClassFileTransformer {
298: private final ClassTransformer classTransformer;
299:
300: public PersistenceClassFileTransformer(
301: ClassTransformer classTransformer) {
302: this .classTransformer = classTransformer;
303: }
304:
305: public byte[] transform(ClassLoader classLoader,
306: String className, Class<?> classBeingRedefined,
307: ProtectionDomain protectionDomain,
308: byte[] classfileBuffer)
309: throws IllegalClassFormatException {
310: // Example code to easily debug transformation of a specific class
311: // if ("org/apache/openejb/test/entity/cmp/BasicCmpBean".equals(className) ||
312: // "org/apache/openejb/test/entity/cmp/BasicCmp2Bean_BasicCmp2Bean".equals(className)) {
313: // System.err.println("Loading " + className);
314: // }
315: byte[] bytes = classTransformer.transform(classLoader,
316: className.replace('/', '.'), classBeingRedefined,
317: protectionDomain, classfileBuffer);
318: return bytes;
319: }
320: }
321: }
|