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.LinkedHashSet;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.Set;
025:
026: import javax.xml.namespace.QName;
027:
028: import org.apache.geronimo.common.DeploymentException;
029: import org.apache.geronimo.gbean.AbstractName;
030: import org.apache.geronimo.gbean.AbstractNameQuery;
031: import org.apache.geronimo.gbean.GBeanData;
032: import org.apache.geronimo.gbean.GBeanInfo;
033: import org.apache.geronimo.gbean.GBeanInfoBuilder;
034: import org.apache.geronimo.j2ee.deployment.Module;
035: import org.apache.geronimo.j2ee.deployment.NamingBuilder;
036: import org.apache.geronimo.j2ee.deployment.annotation.PersistenceContextAnnotationHelper;
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.PersistenceContextReference;
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.GerPersistenceContextRefDocument;
047: import org.apache.geronimo.xbeans.geronimo.naming.GerPersistenceContextRefType;
048: import org.apache.geronimo.xbeans.geronimo.naming.GerPersistenceContextTypeType;
049: import org.apache.geronimo.xbeans.geronimo.naming.GerPropertyType;
050: import org.apache.geronimo.xbeans.javaee.PersistenceContextRefType;
051: import org.apache.geronimo.xbeans.javaee.PersistenceContextTypeType;
052: import org.apache.geronimo.xbeans.javaee.PropertyType;
053: import org.apache.xmlbeans.QNameSet;
054: import org.apache.xmlbeans.XmlObject;
055:
056: /**
057: * @version $Rev: 535381 $ $Date: 2007-05-04 14:04:18 -0700 (Fri, 04 May 2007) $
058: */
059: public class PersistenceContextRefBuilder extends AbstractNamingBuilder {
060: private static final QName PERSISTENCE_CONTEXT_REF_QNAME = new QName(
061: JEE_NAMESPACE, "persistence-context-ref");
062: private static final QNameSet PERSISTENCE_CONTEXT_REF_QNAME_SET = QNameSet
063: .singleton(PERSISTENCE_CONTEXT_REF_QNAME);
064: private static final QName GER_PERSISTENCE_CONTEXT_REF_QNAME = GerPersistenceContextRefDocument.type
065: .getDocumentElementName();
066: private static final QNameSet GER_PERSISTENCE_CONTEXT_REF_QNAME_SET = QNameSet
067: .singleton(GER_PERSISTENCE_CONTEXT_REF_QNAME);
068: private static final Set<String> PERSISTENCE_UNIT_INTERFACE_TYPES = Collections
069: .singleton("org.apache.geronimo.persistence.PersistenceUnitGBean");
070: private final AbstractNameQuery defaultPersistenceUnitAbstractNameQuery;
071: private final boolean strictMatching;
072:
073: public PersistenceContextRefBuilder(Environment defaultEnvironment,
074: AbstractNameQuery defaultPersistenceUnitAbstractNameQuery,
075: boolean strictMatching) {
076: super (defaultEnvironment);
077: this .defaultPersistenceUnitAbstractNameQuery = defaultPersistenceUnitAbstractNameQuery;
078: this .strictMatching = strictMatching;
079: }
080:
081: protected boolean willMergeEnvironment(XmlObject specDD,
082: XmlObject plan) throws DeploymentException {
083: return plan != null
084: && plan
085: .selectChildren(PersistenceContextRefBuilder.GER_PERSISTENCE_CONTEXT_REF_QNAME_SET).length > 0;
086: }
087:
088: public void buildNaming(XmlObject specDD, XmlObject plan,
089: Module module, Map componentContext)
090: throws DeploymentException {
091:
092: // Discover and process any @PersistenceContextRef annotations (if !metadata-complete)
093: if ((module != null) && (module.getClassFinder() != null)) {
094: processAnnotations(module);
095: }
096:
097: List<PersistenceContextRefType> specPersistenceContextRefsUntyped = convert(
098: specDD
099: .selectChildren(PERSISTENCE_CONTEXT_REF_QNAME_SET),
100: JEE_CONVERTER, PersistenceContextRefType.class,
101: PersistenceContextRefType.type);
102: Map<String, GerPersistenceContextRefType> gerPersistenceContextRefsUntyped = getGerPersistenceContextRefs(plan);
103: List<DeploymentException> problems = new ArrayList<DeploymentException>();
104: Configuration localConfiguration = module.getEarContext()
105: .getConfiguration();
106: for (PersistenceContextRefType persistenceContextRef : specPersistenceContextRefsUntyped) {
107: try {
108: String persistenceContextRefName = persistenceContextRef
109: .getPersistenceContextRefName()
110: .getStringValue().trim();
111:
112: addInjections(
113: persistenceContextRefName,
114: persistenceContextRef.getInjectionTargetArray(),
115: componentContext);
116: PersistenceContextTypeType persistenceContextType = persistenceContextRef
117: .getPersistenceContextType();
118: boolean transactionScoped = persistenceContextType == null
119: || !persistenceContextType.getStringValue()
120: .equalsIgnoreCase("extended");
121:
122: PropertyType[] propertyTypes = persistenceContextRef
123: .getPersistencePropertyArray();
124: Map<String, String> properties = new HashMap<String, String>();
125: for (PropertyType propertyType : propertyTypes) {
126: String key = propertyType.getName()
127: .getStringValue();
128: String value = propertyType.getValue()
129: .getStringValue();
130: properties.put(key, value);
131: }
132:
133: AbstractNameQuery persistenceUnitNameQuery;
134: GerPersistenceContextRefType gerPersistenceContextRef = gerPersistenceContextRefsUntyped
135: .remove(persistenceContextRefName);
136: if (gerPersistenceContextRef != null) {
137: persistenceUnitNameQuery = findPersistenceUnit(gerPersistenceContextRef);
138: addProperties(gerPersistenceContextRef, properties);
139: checkForGBean(localConfiguration,
140: persistenceUnitNameQuery, true);
141: } else if (persistenceContextRef
142: .isSetPersistenceUnitName()
143: && persistenceContextRef
144: .getPersistenceUnitName()
145: .getStringValue().trim().length() > 0) {
146: String persistenceUnitName = persistenceContextRef
147: .getPersistenceUnitName().getStringValue()
148: .trim();
149: persistenceUnitNameQuery = new AbstractNameQuery(
150: null, Collections.singletonMap("name",
151: persistenceUnitName),
152: PERSISTENCE_UNIT_INTERFACE_TYPES);
153: if (!checkForGBean(localConfiguration,
154: persistenceUnitNameQuery, strictMatching)) {
155: persistenceUnitName = "persistence/"
156: + persistenceUnitName;
157: persistenceUnitNameQuery = new AbstractNameQuery(
158: null, Collections.singletonMap("name",
159: persistenceUnitName),
160: PERSISTENCE_UNIT_INTERFACE_TYPES);
161: checkForGBean(localConfiguration,
162: persistenceUnitNameQuery, true);
163: }
164: } else {
165: persistenceUnitNameQuery = new AbstractNameQuery(
166: null, Collections.EMPTY_MAP,
167: PERSISTENCE_UNIT_INTERFACE_TYPES);
168: Set<AbstractNameQuery> patterns = Collections
169: .singleton(persistenceUnitNameQuery);
170: LinkedHashSet<GBeanData> gbeans = localConfiguration
171: .findGBeanDatas(localConfiguration,
172: patterns);
173: persistenceUnitNameQuery = checkForDefaultPersistenceUnit(gbeans);
174: if (gbeans.isEmpty()) {
175: gbeans = localConfiguration
176: .findGBeanDatas(patterns);
177: persistenceUnitNameQuery = checkForDefaultPersistenceUnit(gbeans);
178:
179: if (gbeans.isEmpty()) {
180: if (defaultPersistenceUnitAbstractNameQuery == null) {
181: throw new DeploymentException(
182: "No default PersistenceUnit specified, and none located");
183: }
184: persistenceUnitNameQuery = defaultPersistenceUnitAbstractNameQuery;
185: }
186: }
187: checkForGBean(localConfiguration,
188: persistenceUnitNameQuery, true);
189: }
190:
191: PersistenceContextReference reference = new PersistenceContextReference(
192: module.getConfigId(), persistenceUnitNameQuery,
193: transactionScoped, properties);
194:
195: NamingBuilder.JNDI_KEY.get(componentContext).put(
196: ENV + persistenceContextRefName, reference);
197: } catch (DeploymentException e) {
198: problems.add(e);
199: }
200: }
201:
202: // Support persistence context refs that are mentioned only in the geronimo plan
203: for (GerPersistenceContextRefType gerPersistenceContextRef : gerPersistenceContextRefsUntyped
204: .values()) {
205: try {
206: String persistenceContextRefName = gerPersistenceContextRef
207: .getPersistenceContextRefName();
208: GerPersistenceContextTypeType.Enum persistenceContextType = gerPersistenceContextRef
209: .getPersistenceContextType();
210: boolean transactionScoped = persistenceContextType == null
211: || !persistenceContextType
212: .equals(GerPersistenceContextTypeType.EXTENDED);
213: Map properties = new HashMap();
214: addProperties(gerPersistenceContextRef, properties);
215:
216: AbstractNameQuery persistenceUnitNameQuery = findPersistenceUnit(gerPersistenceContextRef);
217:
218: checkForGBean(localConfiguration,
219: persistenceUnitNameQuery, true);
220:
221: PersistenceContextReference reference = new PersistenceContextReference(
222: module.getConfigId(), persistenceUnitNameQuery,
223: transactionScoped, properties);
224:
225: getJndiContextMap(componentContext).put(
226: ENV + persistenceContextRefName, reference);
227: } catch (DeploymentException e) {
228: problems.add(e);
229: }
230:
231: }
232: if (!problems.isEmpty()) {
233: // something is broken with cmp references that stops deployment... this is just a patch around the real problem
234: // throw new DeploymentException("Could not resolve reference at deploy time for query " + persistenceUnitNameQuery, e);
235: for (DeploymentException e : problems) {
236: e.printStackTrace();
237: }
238: //TODO throw a "multi-exception"
239: }
240: }
241:
242: private AbstractNameQuery checkForDefaultPersistenceUnit(
243: LinkedHashSet<GBeanData> gbeans) throws DeploymentException {
244: AbstractNameQuery persistenceUnitNameQuery = null;
245: for (java.util.Iterator it = gbeans.iterator(); it.hasNext();) {
246: GBeanData gbean = (GBeanData) it.next();
247: AbstractName name = gbean.getAbstractName();
248: Map nameMap = name.getName();
249: if ("cmp".equals(nameMap.get("name"))) {
250: it.remove();
251: } else {
252: persistenceUnitNameQuery = new AbstractNameQuery(name);
253: }
254: }
255: if (gbeans.size() > 1) {
256: throw new DeploymentException(
257: "Too many matches for no-name persistence unit: "
258: + gbeans);
259: }
260: return persistenceUnitNameQuery;
261: }
262:
263: private boolean checkForGBean(Configuration localConfiguration,
264: AbstractNameQuery persistenceUnitNameQuery,
265: boolean complainIfMissing) throws DeploymentException {
266: try {
267: localConfiguration.findGBeanData(persistenceUnitNameQuery);
268: return true;
269: } catch (GBeanNotFoundException e) {
270: if (complainIfMissing || e.hasMatches()) {
271: String reason = e.hasMatches() ? "More than one GBean reference found."
272: : "No GBeans found.";
273: throw new DeploymentException(
274: "Could not resolve reference at deploy time for query "
275: + persistenceUnitNameQuery + ". "
276: + reason, e);
277: }
278: return false;
279: }
280: }
281:
282: private void addProperties(
283: GerPersistenceContextRefType persistenceContextRef,
284: Map<String, String> properties) {
285: GerPropertyType[] propertyTypes = persistenceContextRef
286: .getPropertyArray();
287: for (GerPropertyType propertyType : propertyTypes) {
288: String key = propertyType.getKey();
289: String value = propertyType.getValue();
290: properties.put(key, value);
291: }
292: }
293:
294: private Map<String, GerPersistenceContextRefType> getGerPersistenceContextRefs(
295: XmlObject plan) throws DeploymentException {
296: Map<String, GerPersistenceContextRefType> map = new HashMap<String, GerPersistenceContextRefType>();
297: if (plan != null) {
298: List<GerPersistenceContextRefType> refs = convert(
299: plan
300: .selectChildren(GER_PERSISTENCE_CONTEXT_REF_QNAME_SET),
301: NAMING_CONVERTER,
302: GerPersistenceContextRefType.class,
303: GerPersistenceContextRefType.type);
304: for (GerPersistenceContextRefType ref : refs) {
305: map.put(ref.getPersistenceContextRefName().trim(), ref);
306: }
307: }
308: return map;
309: }
310:
311: private AbstractNameQuery findPersistenceUnit(
312: GerPersistenceContextRefType persistenceContextRef) {
313: AbstractNameQuery persistenceUnitNameQuery;
314: if (persistenceContextRef.isSetPersistenceUnitName()) {
315: String persistenceUnitName = persistenceContextRef
316: .getPersistenceUnitName();
317: persistenceUnitNameQuery = new AbstractNameQuery(null,
318: Collections.singletonMap("name",
319: persistenceUnitName),
320: PERSISTENCE_UNIT_INTERFACE_TYPES);
321: } else {
322: GerPatternType gbeanLocator = persistenceContextRef
323: .getPattern();
324:
325: persistenceUnitNameQuery = buildAbstractNameQuery(
326: gbeanLocator, null, null,
327: PERSISTENCE_UNIT_INTERFACE_TYPES);
328: }
329: return persistenceUnitNameQuery;
330: }
331:
332: private void processAnnotations(Module module)
333: throws DeploymentException {
334: // Process all the annotations for this naming builder type
335: PersistenceContextAnnotationHelper.processAnnotations(module
336: .getAnnotatedApp(), module.getClassFinder());
337: }
338:
339: public QNameSet getSpecQNameSet() {
340: SchemaConversionUtils.registerNamespaceConversions(Collections
341: .singletonMap(GER_PERSISTENCE_CONTEXT_REF_QNAME
342: .getLocalPart(), new NamespaceElementConverter(
343: GER_PERSISTENCE_CONTEXT_REF_QNAME
344: .getNamespaceURI())));
345: return QNameSet.EMPTY;
346: }
347:
348: public QNameSet getPlanQNameSet() {
349: return GER_PERSISTENCE_CONTEXT_REF_QNAME_SET;
350: }
351:
352: public static final GBeanInfo GBEAN_INFO;
353:
354: static {
355: GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(
356: PersistenceContextRefBuilder.class,
357: NameFactory.MODULE_BUILDER);
358: infoBuilder.addAttribute("defaultEnvironment",
359: Environment.class, true, true);
360: infoBuilder.addAttribute(
361: "defaultPersistenceUnitAbstractNameQuery",
362: AbstractNameQuery.class, true, true);
363: infoBuilder.addAttribute("strictMatching", boolean.class, true,
364: true);
365:
366: infoBuilder.setConstructor(new String[] { "defaultEnvironment",
367: "defaultPersistenceUnitAbstractNameQuery",
368: "strictMatching" });
369: GBEAN_INFO = infoBuilder.getBeanInfo();
370: }
371:
372: public static GBeanInfo getGBeanInfo() {
373: return GBEAN_INFO;
374: }
375: }
|