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