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.util.ArrayList;
019: import java.util.Collections;
020: import java.util.HashMap;
021: import java.util.List;
022: import java.util.Map;
023: import java.util.Set;
024: import java.util.LinkedHashSet;
025:
026: import javax.xml.namespace.QName;
027:
028: import org.apache.geronimo.common.DeploymentException;
029: import org.apache.geronimo.gbean.AbstractNameQuery;
030: import org.apache.geronimo.gbean.GBeanInfo;
031: import org.apache.geronimo.gbean.GBeanInfoBuilder;
032: import org.apache.geronimo.gbean.GBeanData;
033: import org.apache.geronimo.gbean.AbstractName;
034: import org.apache.geronimo.j2ee.deployment.Module;
035: import org.apache.geronimo.j2ee.deployment.NamingBuilder;
036: import org.apache.geronimo.j2ee.deployment.annotation.PersistenceUnitAnnotationHelper;
037: import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
038: import org.apache.geronimo.kernel.GBeanNotFoundException;
039: import org.apache.geronimo.kernel.config.Configuration;
040: import org.apache.geronimo.kernel.repository.Environment;
041: import org.apache.geronimo.naming.deployment.AbstractNamingBuilder;
042: import org.apache.geronimo.naming.reference.PersistenceUnitReference;
043: import org.apache.geronimo.schema.NamespaceElementConverter;
044: import org.apache.geronimo.schema.SchemaConversionUtils;
045: import org.apache.geronimo.xbeans.geronimo.naming.GerPatternType;
046: import org.apache.geronimo.xbeans.geronimo.naming.GerPersistenceUnitRefDocument;
047: import org.apache.geronimo.xbeans.geronimo.naming.GerPersistenceUnitRefType;
048: import org.apache.geronimo.xbeans.javaee.PersistenceUnitRefType;
049: import org.apache.xmlbeans.QNameSet;
050: import org.apache.xmlbeans.XmlObject;
051:
052: /**
053: * @version $Rev: 535381 $ $Date: 2007-05-04 14:04:18 -0700 (Fri, 04 May 2007) $
054: */
055: public class PersistenceUnitRefBuilder extends AbstractNamingBuilder {
056: private static final QName PERSISTENCE_UNIT_REF_QNAME = new QName(
057: JEE_NAMESPACE, "persistence-unit-ref");
058: private static final QNameSet PERSISTENCE_UNIT_REF_QNAME_SET = QNameSet
059: .singleton(PERSISTENCE_UNIT_REF_QNAME);
060: private static final QName GER_PERSISTENCE_UNIT_REF_QNAME = GerPersistenceUnitRefDocument.type
061: .getDocumentElementName();
062: private static final QNameSet GER_PERSISTENCE_UNIT_REF_QNAME_SET = QNameSet
063: .singleton(GER_PERSISTENCE_UNIT_REF_QNAME);
064: private static final Set PERSISTENCE_UNIT_INTERFACE_TYPES = Collections
065: .singleton("org.apache.geronimo.persistence.PersistenceUnitGBean");
066: private final AbstractNameQuery defaultPersistenceUnitAbstractNameQuery;
067: private final boolean strictMatching;
068:
069: public PersistenceUnitRefBuilder(Environment defaultEnvironment,
070: AbstractNameQuery defaultPersistenceUnitAbstractNameQuery,
071: boolean strictMatching) {
072: super (defaultEnvironment);
073: this .defaultPersistenceUnitAbstractNameQuery = defaultPersistenceUnitAbstractNameQuery;
074: this .strictMatching = strictMatching;
075: }
076:
077: protected boolean willMergeEnvironment(XmlObject specDD,
078: XmlObject plan) throws DeploymentException {
079: if (specDD != null
080: && specDD
081: .selectChildren(PersistenceUnitRefBuilder.PERSISTENCE_UNIT_REF_QNAME_SET).length > 0) {
082: return true;
083: }
084: return plan != null
085: && plan
086: .selectChildren(PersistenceUnitRefBuilder.GER_PERSISTENCE_UNIT_REF_QNAME_SET).length > 0;
087: }
088:
089: public void buildNaming(XmlObject specDD, XmlObject plan,
090: Module module, Map componentContext)
091: throws DeploymentException {
092: Configuration localConfiguration = module.getEarContext()
093: .getConfiguration();
094: // Discover and process any @PersistenceUnitRef annotations (if !metadata-complete)
095: if (module.getClassFinder() != null) {
096: processAnnotations(module);
097: }
098:
099: List<PersistenceUnitRefType> specPersistenceUnitRefsUntyped = convert(
100: specDD
101: .selectChildren(PersistenceUnitRefBuilder.PERSISTENCE_UNIT_REF_QNAME_SET),
102: JEE_CONVERTER, PersistenceUnitRefType.class,
103: PersistenceUnitRefType.type);
104: Map<String, GerPersistenceUnitRefType> gerPersistenceUnitRefsUntyped = getGerPersistenceUnitRefs(plan);
105: List<DeploymentException> problems = new ArrayList<DeploymentException>();
106: for (PersistenceUnitRefType persistenceUnitRef : specPersistenceUnitRefsUntyped) {
107: try {
108: String persistenceUnitRefName = persistenceUnitRef
109: .getPersistenceUnitRefName().getStringValue()
110: .trim();
111:
112: addInjections(persistenceUnitRefName,
113: persistenceUnitRef.getInjectionTargetArray(),
114: componentContext);
115: AbstractNameQuery persistenceUnitNameQuery;
116: GerPersistenceUnitRefType gerPersistenceUnitRef = gerPersistenceUnitRefsUntyped
117: .remove(persistenceUnitRefName);
118: if (gerPersistenceUnitRef != null) {
119: persistenceUnitNameQuery = findPersistenceUnit(gerPersistenceUnitRef);
120: checkForGBean(localConfiguration,
121: persistenceUnitNameQuery, true);
122: } else if (persistenceUnitRef
123: .isSetPersistenceUnitName()
124: && persistenceUnitRef.getPersistenceUnitName()
125: .getStringValue().trim().length() > 0) {
126: String persistenceUnitName = persistenceUnitRef
127: .getPersistenceUnitName().getStringValue()
128: .trim();
129: persistenceUnitNameQuery = new AbstractNameQuery(
130: null, Collections.singletonMap("name",
131: persistenceUnitName),
132: PERSISTENCE_UNIT_INTERFACE_TYPES);
133: if (!checkForGBean(localConfiguration,
134: persistenceUnitNameQuery, strictMatching)) {
135: persistenceUnitName = "persistence/"
136: + persistenceUnitName;
137: persistenceUnitNameQuery = new AbstractNameQuery(
138: null, Collections.singletonMap("name",
139: persistenceUnitName),
140: PERSISTENCE_UNIT_INTERFACE_TYPES);
141: checkForGBean(localConfiguration,
142: persistenceUnitNameQuery, true);
143: }
144: } else {
145: persistenceUnitNameQuery = new AbstractNameQuery(
146: null, Collections.EMPTY_MAP,
147: PERSISTENCE_UNIT_INTERFACE_TYPES);
148: Set<AbstractNameQuery> patterns = Collections
149: .singleton(persistenceUnitNameQuery);
150: LinkedHashSet<GBeanData> gbeans = localConfiguration
151: .findGBeanDatas(localConfiguration,
152: patterns);
153: persistenceUnitNameQuery = checkForDefaultPersistenceUnit(gbeans);
154: if (gbeans.isEmpty()) {
155: gbeans = localConfiguration
156: .findGBeanDatas(patterns);
157: persistenceUnitNameQuery = checkForDefaultPersistenceUnit(gbeans);
158:
159: if (gbeans.isEmpty()) {
160: if (defaultPersistenceUnitAbstractNameQuery == null) {
161: throw new DeploymentException(
162: "No default PersistenceUnit specified, and none located");
163: }
164: persistenceUnitNameQuery = defaultPersistenceUnitAbstractNameQuery;
165: }
166: }
167: }
168: checkForGBean(localConfiguration,
169: persistenceUnitNameQuery, true);
170:
171: PersistenceUnitReference reference = new PersistenceUnitReference(
172: module.getConfigId(), persistenceUnitNameQuery);
173:
174: NamingBuilder.JNDI_KEY.get(componentContext).put(
175: ENV + persistenceUnitRefName, reference);
176: } catch (DeploymentException e) {
177: problems.add(e);
178: }
179:
180: }
181:
182: for (GerPersistenceUnitRefType gerPersistenceUnitRef : gerPersistenceUnitRefsUntyped
183: .values()) {
184: try {
185: String PersistenceUnitRefName = gerPersistenceUnitRef
186: .getPersistenceUnitRefName();
187:
188: AbstractNameQuery persistenceUnitNameQuery = findPersistenceUnit(gerPersistenceUnitRef);
189:
190: checkForGBean(localConfiguration,
191: persistenceUnitNameQuery, true);
192:
193: PersistenceUnitReference reference = new PersistenceUnitReference(
194: module.getConfigId(), persistenceUnitNameQuery);
195:
196: NamingBuilder.JNDI_KEY.get(componentContext).put(
197: ENV + PersistenceUnitRefName, reference);
198: } catch (DeploymentException e) {
199: problems.add(e);
200: }
201:
202: }
203: if (!problems.isEmpty()) {
204: //TODO make DeploymentException accept a list of exceptions as causes.
205: throw new DeploymentException(
206: "At least one deployment problem:" + problems);
207: }
208: }
209:
210: private AbstractNameQuery checkForDefaultPersistenceUnit(
211: LinkedHashSet<GBeanData> gbeans) throws DeploymentException {
212: AbstractNameQuery persistenceUnitNameQuery = null;
213: for (java.util.Iterator it = gbeans.iterator(); it.hasNext();) {
214: GBeanData gbean = (GBeanData) it.next();
215: AbstractName name = gbean.getAbstractName();
216: Map nameMap = name.getName();
217: if ("cmp".equals(nameMap.get("name"))) {
218: it.remove();
219: } else {
220: persistenceUnitNameQuery = new AbstractNameQuery(name);
221: }
222: }
223: if (gbeans.size() > 1) {
224: throw new DeploymentException(
225: "Too many matches for no-name persistence unit: "
226: + gbeans);
227: }
228: return persistenceUnitNameQuery;
229: }
230:
231: private boolean checkForGBean(Configuration localConfiguration,
232: AbstractNameQuery persistenceUnitNameQuery,
233: boolean complainIfMissing) throws DeploymentException {
234: try {
235: localConfiguration.findGBeanData(persistenceUnitNameQuery);
236: return true;
237: } catch (GBeanNotFoundException e) {
238: if (complainIfMissing || e.hasMatches()) {
239: String reason = e.hasMatches() ? "More than one GBean reference found."
240: : "No GBean references found.";
241: throw new DeploymentException(
242: "Could not resolve reference at deploy time for query "
243: + persistenceUnitNameQuery + ". "
244: + reason, e);
245: }
246: return false;
247: }
248: }
249:
250: private void processAnnotations(Module module)
251: throws DeploymentException {
252: // Process all the annotations for this naming builder type
253: PersistenceUnitAnnotationHelper.processAnnotations(module
254: .getAnnotatedApp(), module.getClassFinder());
255: }
256:
257: private AbstractNameQuery findPersistenceUnit(
258: GerPersistenceUnitRefType gerPersistenceUnitRef) {
259: AbstractNameQuery persistenceUnitNameQuery;
260: if (gerPersistenceUnitRef.isSetPersistenceUnitName()) {
261: String persistenceUnitName = gerPersistenceUnitRef
262: .getPersistenceUnitName();
263: persistenceUnitNameQuery = new AbstractNameQuery(null,
264: Collections.singletonMap("name",
265: persistenceUnitName),
266: PERSISTENCE_UNIT_INTERFACE_TYPES);
267: } else {
268: GerPatternType gbeanLocator = gerPersistenceUnitRef
269: .getPattern();
270:
271: persistenceUnitNameQuery = buildAbstractNameQuery(
272: gbeanLocator, null, null,
273: PERSISTENCE_UNIT_INTERFACE_TYPES);
274: }
275: return persistenceUnitNameQuery;
276: }
277:
278: public QNameSet getSpecQNameSet() {
279: SchemaConversionUtils
280: .registerNamespaceConversions(Collections
281: .singletonMap(
282: PersistenceUnitRefBuilder.GER_PERSISTENCE_UNIT_REF_QNAME
283: .getLocalPart(),
284: new NamespaceElementConverter(
285: PersistenceUnitRefBuilder.GER_PERSISTENCE_UNIT_REF_QNAME
286: .getNamespaceURI())));
287: return PERSISTENCE_UNIT_REF_QNAME_SET;
288: }
289:
290: public QNameSet getPlanQNameSet() {
291: return GER_PERSISTENCE_UNIT_REF_QNAME_SET;
292: }
293:
294: private Map<String, GerPersistenceUnitRefType> getGerPersistenceUnitRefs(
295: XmlObject plan) throws DeploymentException {
296: Map<String, GerPersistenceUnitRefType> map = new HashMap<String, GerPersistenceUnitRefType>();
297: if (plan != null) {
298: List<GerPersistenceUnitRefType> refs = convert(
299: plan
300: .selectChildren(PersistenceUnitRefBuilder.GER_PERSISTENCE_UNIT_REF_QNAME_SET),
301: NAMING_CONVERTER, GerPersistenceUnitRefType.class,
302: GerPersistenceUnitRefType.type);
303: for (GerPersistenceUnitRefType ref : refs) {
304: map.put(ref.getPersistenceUnitRefName().trim(), ref);
305: }
306: }
307: return map;
308: }
309:
310: public static final GBeanInfo GBEAN_INFO;
311:
312: static {
313: GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(
314: PersistenceUnitRefBuilder.class,
315: NameFactory.MODULE_BUILDER);
316: infoBuilder.addAttribute("defaultEnvironment",
317: Environment.class, true, true);
318: infoBuilder.addAttribute(
319: "defaultPersistenceUnitAbstractNameQuery",
320: AbstractNameQuery.class, true, true);
321: infoBuilder.addAttribute("strictMatching", boolean.class, true,
322: true);
323:
324: infoBuilder.setConstructor(new String[] { "defaultEnvironment",
325: "defaultPersistenceUnitAbstractNameQuery",
326: "strictMatching" });
327: GBEAN_INFO = infoBuilder.getBeanInfo();
328: }
329:
330: public static GBeanInfo getGBeanInfo() {
331: return PersistenceUnitRefBuilder.GBEAN_INFO;
332: }
333: }
|