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.geronimo.persistence.builder;
017:
018: import java.io.File;
019: import java.io.IOException;
020: import java.net.URI;
021: import java.net.URISyntaxException;
022: import java.net.URL;
023: import java.util.ArrayList;
024: import java.util.Collection;
025: import java.util.HashMap;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.Properties;
029: import java.util.jar.JarFile;
030:
031: import javax.xml.namespace.QName;
032:
033: import org.apache.geronimo.common.DeploymentException;
034: import org.apache.geronimo.deployment.ClassPathList;
035: import org.apache.geronimo.deployment.ModuleIDBuilder;
036: import org.apache.geronimo.deployment.service.EnvironmentBuilder;
037: import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
038: import org.apache.geronimo.gbean.AbstractName;
039: import org.apache.geronimo.gbean.AbstractNameQuery;
040: import org.apache.geronimo.gbean.GBeanData;
041: import org.apache.geronimo.gbean.GBeanInfo;
042: import org.apache.geronimo.gbean.GBeanInfoBuilder;
043: import org.apache.geronimo.j2ee.deployment.EARContext;
044: import org.apache.geronimo.j2ee.deployment.Module;
045: import org.apache.geronimo.j2ee.deployment.ModuleBuilderExtension;
046: import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
047: import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
048: import org.apache.geronimo.kernel.Naming;
049: import org.apache.geronimo.kernel.config.ConfigurationStore;
050: import org.apache.geronimo.kernel.repository.Environment;
051: import org.apache.geronimo.naming.ResourceSource;
052: import org.apache.geronimo.persistence.PersistenceUnitGBean;
053: import org.apache.geronimo.xbeans.persistence.PersistenceDocument;
054: import org.apache.xbean.finder.ResourceFinder;
055: import org.apache.xmlbeans.QNameSet;
056: import org.apache.xmlbeans.XmlException;
057: import org.apache.xmlbeans.XmlObject;
058:
059: /**
060: * @version $Rev: 633225 $ $Date: 2008-03-03 10:21:31 -0800 (Mon, 03 Mar 2008) $
061: */
062: public class PersistenceUnitBuilder implements ModuleBuilderExtension {
063: private static final QName PERSISTENCE_QNAME = PersistenceDocument.type
064: .getDocumentElementName();
065:
066: private final Environment defaultEnvironment;
067: private final String defaultPersistenceProviderClassName;
068: private final Properties defaultPersistenceUnitProperties;
069: private final AbstractNameQuery defaultJtaDataSourceName;
070: private final AbstractNameQuery defaultNonJtaDataSourceName;
071: private final AbstractNameQuery extendedEntityManagerRegistryName;
072: private static final String ANON_PU_NAME = "AnonymousPersistenceUnit";
073: private static final String RESOURCE_SOURCE_CLASS_NAME = ResourceSource.class
074: .getName();
075:
076: public PersistenceUnitBuilder(Environment defaultEnvironment,
077: String defaultPersistenceProviderClassName,
078: String defaultJtaDataSourceName,
079: String defaultNonJtaDataSourceName,
080: AbstractNameQuery extendedEntityManagerRegistryName,
081: Properties defaultPersistenceUnitProperties)
082: throws URISyntaxException {
083: this .defaultEnvironment = defaultEnvironment;
084: this .defaultPersistenceProviderClassName = defaultPersistenceProviderClassName;
085: this .defaultJtaDataSourceName = defaultJtaDataSourceName == null ? null
086: : getAbstractNameQuery(defaultJtaDataSourceName);
087: this .defaultNonJtaDataSourceName = defaultNonJtaDataSourceName == null ? null
088: : getAbstractNameQuery(defaultNonJtaDataSourceName);
089: this .extendedEntityManagerRegistryName = extendedEntityManagerRegistryName;
090: this .defaultPersistenceUnitProperties = defaultPersistenceUnitProperties == null ? new Properties()
091: : defaultPersistenceUnitProperties;
092: }
093:
094: public void createModule(Module module, Object plan,
095: JarFile moduleFile, String targetPath, URL specDDUrl,
096: Environment environment, Object moduleContextInfo,
097: AbstractName earName, Naming naming,
098: ModuleIDBuilder idBuilder) throws DeploymentException {
099: }
100:
101: public void installModule(JarFile earFile, EARContext earContext,
102: Module module, Collection configurationStores,
103: ConfigurationStore targetConfigurationStore,
104: Collection repository) throws DeploymentException {
105: }
106:
107: public void initContext(EARContext earContext, Module module,
108: ClassLoader cl) throws DeploymentException {
109: XmlObject container = module.getVendorDD();
110: EARContext moduleContext = module.getEarContext();
111: XmlObject[] raws = container.selectChildren(PERSISTENCE_QNAME);
112:
113: Map<String, PersistenceDocument.Persistence.PersistenceUnit> overrides = new HashMap<String, PersistenceDocument.Persistence.PersistenceUnit>();
114: for (XmlObject raw : raws) {
115: PersistenceDocument.Persistence persistence = (PersistenceDocument.Persistence) raw
116: .copy().changeType(
117: PersistenceDocument.Persistence.type);
118: for (PersistenceDocument.Persistence.PersistenceUnit unit : persistence
119: .getPersistenceUnitArray()) {
120: overrides.put(unit.getName().trim(), unit);
121: }
122: // buildPersistenceUnits(persistence, module, module.getTargetPath());
123: }
124: try {
125: File rootBaseFile = module.getRootEarContext()
126: .getConfiguration().getConfigurationDir();
127: String rootBase = rootBaseFile.toURI().normalize()
128: .toString();
129: URI moduleBaseURI = moduleContext.getBaseDir().toURI();
130: Map rootGeneralData = module.getRootEarContext()
131: .getGeneralData();
132: ClassPathList manifestcp = (ClassPathList) module
133: .getEarContext().getGeneralData().get(
134: ClassPathList.class);
135: if (manifestcp == null) {
136: manifestcp = new ClassPathList();
137: manifestcp.add(module.getTargetPath());
138: }
139: URL[] urls = new URL[manifestcp.size()];
140: int i = 0;
141: for (String path : manifestcp) {
142: path = path.replaceAll(" ", "%20");
143: URL url = moduleBaseURI.resolve(path).toURL();
144: urls[i++] = url;
145: }
146: ResourceFinder finder = new ResourceFinder("", null, urls);
147: List<URL> knownPersistenceUrls = (List<URL>) rootGeneralData
148: .get(PersistenceUnitBuilder.class.getName());
149: if (knownPersistenceUrls == null) {
150: knownPersistenceUrls = new ArrayList<URL>();
151: rootGeneralData.put(PersistenceUnitBuilder.class
152: .getName(), knownPersistenceUrls);
153: }
154: List<URL> persistenceUrls = finder
155: .findAll("META-INF/persistence.xml");
156: persistenceUrls.removeAll(knownPersistenceUrls);
157: if (raws.length > 0 || persistenceUrls.size() > 0) {
158: EnvironmentBuilder.mergeEnvironments(module
159: .getEnvironment(), defaultEnvironment);
160: }
161: for (URL persistenceUrl : persistenceUrls) {
162: String persistenceLocation;
163: try {
164: persistenceLocation = persistenceUrl.toURI()
165: .toString();
166: } catch (URISyntaxException e) {
167: //????
168: continue;
169: }
170: int pos = persistenceLocation.indexOf(rootBase);
171: if (pos < 0) {
172: //not in the ear
173: continue;
174: }
175: int endPos = persistenceLocation.lastIndexOf("!/");
176: if (endPos < 0) {
177: // if unable to find the '!/' marker, try to see if this is
178: // a war file with the persistence.xml directly embeded - no ejb-jar
179: endPos = persistenceLocation
180: .lastIndexOf("META-INF");
181: }
182: if (endPos >= 0) {
183: //path relative to ear base uri
184: String relative = persistenceLocation.substring(pos
185: + rootBase.length(), endPos);
186: //find path relative to module base uri
187: relative = module.getRelativePath(relative);
188: PersistenceDocument persistenceDocument;
189: try {
190: XmlObject xmlObject = XmlBeansUtil.parse(
191: persistenceUrl, moduleContext
192: .getClassLoader());
193: persistenceDocument = (PersistenceDocument) xmlObject
194: .changeType(PersistenceDocument.type);
195: } catch (XmlException e) {
196: throw new DeploymentException(
197: "Could not parse persistence.xml file: "
198: + persistenceUrl, e);
199: }
200: PersistenceDocument.Persistence persistence = persistenceDocument
201: .getPersistence();
202: buildPersistenceUnits(persistence, overrides,
203: module, relative);
204: knownPersistenceUrls.add(persistenceUrl);
205: } else {
206: throw new DeploymentException(
207: "Could not find persistence.xml file: "
208: + persistenceUrl);
209: }
210: }
211: } catch (IOException e) {
212: throw new DeploymentException(
213: "Could not look for META-INF/persistence.xml files",
214: e);
215: }
216:
217: for (PersistenceDocument.Persistence.PersistenceUnit persistenceUnit : overrides
218: .values()) {
219: GBeanData data = installPersistenceUnitGBean(
220: persistenceUnit, module, module.getTargetPath());
221: respectExcludeUnlistedClasses(data);
222: }
223: }
224:
225: public void addGBeans(EARContext earContext, Module module,
226: ClassLoader cl, Collection repository)
227: throws DeploymentException {
228: }
229:
230: private void buildPersistenceUnits(
231: PersistenceDocument.Persistence persistence,
232: Map<String, PersistenceDocument.Persistence.PersistenceUnit> overrides,
233: Module module, String persistenceModulePath)
234: throws DeploymentException {
235: PersistenceDocument.Persistence.PersistenceUnit[] persistenceUnits = persistence
236: .getPersistenceUnitArray();
237: for (PersistenceDocument.Persistence.PersistenceUnit persistenceUnit : persistenceUnits) {
238: GBeanData data = installPersistenceUnitGBean(
239: persistenceUnit, module, persistenceModulePath);
240: String unitName = persistenceUnit.getName().trim();
241: if (overrides.get(unitName) != null) {
242: setOverrideableProperties(overrides.remove(unitName),
243: data);
244: }
245: respectExcludeUnlistedClasses(data);
246: }
247: }
248:
249: private GBeanData installPersistenceUnitGBean(
250: PersistenceDocument.Persistence.PersistenceUnit persistenceUnit,
251: Module module, String persistenceModulePath)
252: throws DeploymentException {
253: EARContext moduleContext = module.getEarContext();
254: String persistenceUnitName = persistenceUnit.getName().trim();
255: if (persistenceUnitName.length() == 0) {
256: persistenceUnitName = ANON_PU_NAME;
257: }
258: AbstractName abstractName;
259: if (persistenceModulePath == null
260: || persistenceModulePath.length() == 0) {
261: abstractName = moduleContext.getNaming().createChildName(
262: module.getModuleName(), persistenceUnitName,
263: PersistenceUnitGBean.GBEAN_INFO.getJ2eeType());
264: } else {
265: abstractName = moduleContext.getNaming().createChildName(
266: module.getModuleName(), persistenceModulePath,
267: NameFactory.PERSISTENCE_UNIT_MODULE);
268: abstractName = moduleContext.getNaming().createChildName(
269: abstractName, persistenceUnitName,
270: PersistenceUnitGBean.GBEAN_INFO.getJ2eeType());
271: }
272: GBeanData gbeanData = new GBeanData(abstractName,
273: PersistenceUnitGBean.GBEAN_INFO);
274: try {
275: moduleContext.addGBean(gbeanData);
276: } catch (GBeanAlreadyExistsException e) {
277: throw new DeploymentException(
278: "Duplicate persistenceUnit name "
279: + persistenceUnitName, e);
280: }
281: gbeanData.setAttribute("persistenceUnitName",
282: persistenceUnitName);
283: gbeanData.setAttribute("persistenceUnitRoot",
284: persistenceModulePath);
285:
286: //set defaults:
287: gbeanData.setAttribute("persistenceProviderClassName",
288: defaultPersistenceProviderClassName);
289: //spec 6.2.1.2 the default is JTA
290: gbeanData.setAttribute("persistenceUnitTransactionType", "JTA");
291: if (defaultJtaDataSourceName != null) {
292: gbeanData.setReferencePattern("JtaDataSourceWrapper",
293: defaultJtaDataSourceName);
294: }
295: if (defaultNonJtaDataSourceName != null) {
296: gbeanData.setReferencePattern("NonJtaDataSourceWrapper",
297: defaultNonJtaDataSourceName);
298: }
299:
300: gbeanData.setAttribute("mappingFileNames",
301: new ArrayList<String>());
302: gbeanData.setAttribute("excludeUnlistedClasses", false);
303: gbeanData.setAttribute("managedClassNames",
304: new ArrayList<String>());
305: gbeanData.setAttribute("jarFileUrls", new ArrayList<String>());
306: Properties properties = new Properties();
307: gbeanData.setAttribute("properties", properties);
308: properties.putAll(defaultPersistenceUnitProperties);
309: AbstractNameQuery transactionManagerName = moduleContext
310: .getTransactionManagerName();
311: gbeanData.setReferencePattern("TransactionManager",
312: transactionManagerName);
313: gbeanData.setReferencePattern("EntityManagerRegistry",
314: extendedEntityManagerRegistryName);
315:
316: setOverrideableProperties(persistenceUnit, gbeanData);
317: return gbeanData;
318: }
319:
320: private void setOverrideableProperties(
321: PersistenceDocument.Persistence.PersistenceUnit persistenceUnit,
322: GBeanData gbeanData) throws DeploymentException {
323: if (persistenceUnit.isSetProvider()) {
324: gbeanData.setAttribute("persistenceProviderClassName",
325: persistenceUnit.getProvider().trim());
326: }
327: if (persistenceUnit.isSetTransactionType()) {
328: gbeanData.setAttribute("persistenceUnitTransactionType",
329: persistenceUnit.getTransactionType().toString());
330: }
331: if (persistenceUnit.isSetJtaDataSource()) {
332: String jtaDataSourceString = persistenceUnit
333: .getJtaDataSource().trim();
334: try {
335: AbstractNameQuery jtaDataSourceNameQuery = getAbstractNameQuery(jtaDataSourceString);
336: gbeanData.setReferencePattern("JtaDataSourceWrapper",
337: jtaDataSourceNameQuery);
338: } catch (URISyntaxException e) {
339: throw new DeploymentException(
340: "Could not create jta-data-source AbstractNameQuery from string: "
341: + jtaDataSourceString, e);
342: }
343: }
344:
345: if (persistenceUnit.isSetNonJtaDataSource()) {
346: String nonJtaDataSourceString = persistenceUnit
347: .getNonJtaDataSource().trim();
348: try {
349: AbstractNameQuery nonJtaDataSourceNameQuery = getAbstractNameQuery(nonJtaDataSourceString);
350: gbeanData.setReferencePattern(
351: "NonJtaDataSourceWrapper",
352: nonJtaDataSourceNameQuery);
353: } catch (URISyntaxException e) {
354: throw new DeploymentException(
355: "Could not create non-jta-data-source AbstractNameQuery from string: "
356: + nonJtaDataSourceString, e);
357: }
358: }
359:
360: List<String> mappingFileNames = (List<String>) gbeanData
361: .getAttribute("mappingFileNames");
362: String[] mappingFileNameStrings = persistenceUnit
363: .getMappingFileArray();
364: for (String mappingFileNameString : mappingFileNameStrings) {
365: mappingFileNames.add(mappingFileNameString.trim());
366: }
367:
368: if (persistenceUnit.isSetExcludeUnlistedClasses()) {
369: gbeanData.setAttribute("excludeUnlistedClasses",
370: persistenceUnit.getExcludeUnlistedClasses());
371: }
372:
373: String[] managedClassNameStrings = persistenceUnit
374: .getClass1Array();
375: List<String> managedClassNames = (List<String>) gbeanData
376: .getAttribute("managedClassNames");
377: for (String managedClassNameString : managedClassNameStrings) {
378: managedClassNames.add(managedClassNameString.trim());
379: }
380: List<String> jarFileUrls = (List<String>) gbeanData
381: .getAttribute("jarFileUrls");
382: //add the specified locations in the ear
383: String[] jarFileUrlStrings = persistenceUnit.getJarFileArray();
384: for (String jarFileUrlString : jarFileUrlStrings) {
385: jarFileUrls.add(jarFileUrlString.trim());
386: }
387:
388: if (persistenceUnit.isSetProperties()) {
389: Properties properties = (Properties) gbeanData
390: .getAttribute("properties");
391: PersistenceDocument.Persistence.PersistenceUnit.Properties.Property[] propertyObjects = persistenceUnit
392: .getProperties().getPropertyArray();
393: for (PersistenceDocument.Persistence.PersistenceUnit.Properties.Property propertyObject : propertyObjects) {
394: String key = propertyObject.getName().trim();
395: String value = propertyObject.getValue().trim();
396: properties.setProperty(key, value);
397: }
398: }
399:
400: }
401:
402: private void respectExcludeUnlistedClasses(GBeanData gbeanData) {
403: boolean excludeUnlistedClasses = (Boolean) gbeanData
404: .getAttribute("excludeUnlistedClasses");
405:
406: if (excludeUnlistedClasses) {
407: gbeanData.clearAttribute("jarFileUrls");
408: } else {
409: gbeanData.clearAttribute("managedClassNames");
410: }
411: }
412:
413: private AbstractNameQuery getAbstractNameQuery(
414: String dataSourceString) throws URISyntaxException {
415: if (dataSourceString.indexOf('=') == -1) {
416: dataSourceString = "?name=" + dataSourceString;
417: }
418: AbstractNameQuery dataSourceNameQuery = new AbstractNameQuery(
419: new URI(dataSourceString + "#"
420: + RESOURCE_SOURCE_CLASS_NAME));
421: return dataSourceNameQuery;
422: }
423:
424: public QNameSet getSpecQNameSet() {
425: return QNameSet.EMPTY;
426: }
427:
428: public QNameSet getPlanQNameSet() {
429: return QNameSet.singleton(PERSISTENCE_QNAME);
430: }
431:
432: public static final GBeanInfo GBEAN_INFO;
433:
434: static {
435: GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(
436: PersistenceUnitBuilder.class,
437: NameFactory.MODULE_BUILDER);
438:
439: infoBuilder.addAttribute("defaultEnvironment",
440: Environment.class, true, true);
441: infoBuilder.addAttribute("defaultPersistenceProviderClassName",
442: String.class, true, true);
443: infoBuilder.addAttribute("defaultJtaDataSourceName",
444: String.class, true, true);
445: infoBuilder.addAttribute("defaultNonJtaDataSourceName",
446: String.class, true, true);
447: infoBuilder.addAttribute("extendedEntityManagerRegistryName",
448: AbstractNameQuery.class, true, true);
449: infoBuilder.addAttribute("defaultPersistenceUnitProperties",
450: Properties.class, true, true);
451:
452: infoBuilder.setConstructor(new String[] { "defaultEnvironment",
453: "defaultPersistenceProviderClassName",
454: "defaultJtaDataSourceName",
455: "defaultNonJtaDataSourceName",
456: "extendedEntityManagerRegistryName",
457: "defaultPersistenceUnitProperties" });
458:
459: GBEAN_INFO = infoBuilder.getBeanInfo();
460:
461: }
462:
463: public static GBeanInfo getGBeanInfo() {
464: return GBEAN_INFO;
465: }
466:
467: }
|