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
018 package org.apache.geronimo.naming.deployment;
019
020 import java.lang.reflect.Field;
021 import java.lang.reflect.Method;
022 import java.util.Collection;
023 import java.util.HashMap;
024 import java.util.Map;
025
026 import javax.annotation.Resource;
027 import javax.xml.namespace.QName;
028
029 import org.apache.commons.logging.Log;
030 import org.apache.commons.logging.LogFactory;
031 import org.apache.geronimo.common.DeploymentException;
032 import org.apache.geronimo.deployment.service.EnvironmentBuilder;
033 import org.apache.geronimo.gbean.GBeanInfo;
034 import org.apache.geronimo.gbean.GBeanInfoBuilder;
035 import org.apache.geronimo.j2ee.deployment.Module;
036 import org.apache.geronimo.j2ee.deployment.annotation.AnnotatedApp;
037 import org.apache.geronimo.j2ee.deployment.annotation.HandlerChainAnnotationHelper;
038 import org.apache.geronimo.j2ee.deployment.annotation.ResourceAnnotationHelper;
039 import org.apache.geronimo.j2ee.deployment.annotation.WebServiceRefAnnotationHelper;
040 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
041 import org.apache.geronimo.kernel.repository.Environment;
042 import org.apache.geronimo.xbeans.geronimo.naming.GerServiceRefDocument;
043 import org.apache.geronimo.xbeans.geronimo.naming.GerServiceRefType;
044 import org.apache.geronimo.xbeans.javaee.DescriptionType;
045 import org.apache.geronimo.xbeans.javaee.FullyQualifiedClassType;
046 import org.apache.geronimo.xbeans.javaee.InjectionTargetType;
047 import org.apache.geronimo.xbeans.javaee.JndiNameType;
048 import org.apache.geronimo.xbeans.javaee.ServiceRefType;
049 import org.apache.geronimo.xbeans.javaee.XsdStringType;
050 import org.apache.xmlbeans.QNameSet;
051 import org.apache.xmlbeans.XmlObject;
052
053 public class SwitchingServiceRefBuilder extends AbstractNamingBuilder {
054
055 private static final Log log = LogFactory.getLog(SwitchingServiceRefBuilder.class);
056
057 private static final QName GER_SERVICE_REF_QNAME = GerServiceRefDocument.type
058 .getDocumentElementName();
059
060 private static final QNameSet GER_SERVICE_REF_QNAME_SET = QNameSet
061 .singleton(GER_SERVICE_REF_QNAME);
062
063 private final QNameSet serviceRefQNameSet;
064
065 private final Collection jaxrpcBuilders;
066
067 private final Collection jaxwsBuilders;
068
069 public SwitchingServiceRefBuilder(String[] eeNamespaces,
070 Collection jaxrpcBuilders,
071 Collection jaxwsBuilders) {
072 super(null);
073 this.jaxrpcBuilders = jaxrpcBuilders;
074 this.jaxwsBuilders = jaxwsBuilders;
075 this.serviceRefQNameSet = buildQNameSet(eeNamespaces, "service-ref");
076 }
077
078 public void buildEnvironment(XmlObject specDD,
079 XmlObject plan,
080 Environment environment)
081 throws DeploymentException {
082 if (this.jaxrpcBuilders != null && !this.jaxrpcBuilders.isEmpty()) {
083 mergeEnvironment(environment, getJAXRCPBuilder());
084 }
085 if (this.jaxwsBuilders != null && !this.jaxwsBuilders.isEmpty()) {
086 mergeEnvironment(environment, getJAXWSBuilder());
087 }
088 }
089
090 public void buildNaming(XmlObject specDD,
091 XmlObject plan,
092 Module module,
093 Map componentContext) throws DeploymentException {
094
095 // Discover and process any @WebServiceRef annotations (if !metadata-complete)
096 if ((module != null) && (module.getClassFinder() != null)) {
097 processAnnotations(module);
098 }
099
100 ClassLoader cl = module.getEarContext().getClassLoader();
101 Class jaxrpcClass = loadClass("javax.xml.rpc.Service", cl);
102 Class jaxwsClass = loadClass("javax.xml.ws.Service", cl);
103
104 XmlObject[] serviceRefs = specDD.selectChildren(serviceRefQNameSet);
105
106 XmlObject[] gerServiceRefsUntyped = plan == null ? NO_REFS : plan
107 .selectChildren(GER_SERVICE_REF_QNAME_SET);
108 Map serviceRefMap = mapServiceRefs(gerServiceRefsUntyped);
109
110 for (XmlObject serviceRef : serviceRefs) {
111 ServiceRefType serviceRefType = (ServiceRefType) convert(
112 serviceRef, JEE_CONVERTER, ServiceRefType.type);
113
114 String name = getStringValue(serviceRefType.getServiceRefName());
115 GerServiceRefType gerServiceRefType = (GerServiceRefType) serviceRefMap.get(name);
116 serviceRefMap.remove(name);
117
118 String serviceInterfaceName = getStringValue(serviceRefType
119 .getServiceInterface());
120 Class serviceInterfaceClass = loadClass(serviceInterfaceName, cl);
121
122 InjectionTargetType[] injections = serviceRefType.getInjectionTargetArray();
123 addInjections(name, injections, componentContext);
124
125 if (jaxrpcClass.isAssignableFrom(serviceInterfaceClass)) {
126 // class jaxrpc handler
127 ServiceRefBuilder jaxrpcBuilder = getJAXRCPBuilder();
128 jaxrpcBuilder.buildNaming(serviceRef, gerServiceRefType,
129 module, componentContext);
130 } else if (jaxwsClass.isAssignableFrom(serviceInterfaceClass)) {
131 // calll jaxws handler
132 ServiceRefBuilder jaxwsBuilder = getJAXWSBuilder();
133 jaxwsBuilder.buildNaming(serviceRef, gerServiceRefType, module,
134 componentContext);
135 } else {
136 throw new DeploymentException(serviceInterfaceName
137 + " does not extend "
138 + jaxrpcClass.getName() + " or "
139 + jaxwsClass.getName());
140 }
141 }
142
143 if (serviceRefMap.size() > 0) {
144 log.warn("Failed to build reference to service reference "+serviceRefMap.keySet()+" defined in plan file, reason - corresponding entry in deployment descriptor missing.");
145 }
146 }
147
148 private ServiceRefBuilder getJAXWSBuilder() throws DeploymentException {
149 ServiceRefBuilder jaxwsBuilder = null;
150 if (this.jaxwsBuilders == null || this.jaxwsBuilders.isEmpty()) {
151 throw new DeploymentException(
152 "No JAX-WS ServiceRefBuilders registered");
153 } else {
154 jaxwsBuilder = (ServiceRefBuilder) this.jaxwsBuilders.iterator()
155 .next();
156 }
157 return jaxwsBuilder;
158 }
159
160 private ServiceRefBuilder getJAXRCPBuilder() throws DeploymentException {
161 ServiceRefBuilder jaxrpcBuilder = null;
162 if (this.jaxrpcBuilders == null || this.jaxrpcBuilders.isEmpty()) {
163 throw new DeploymentException(
164 "No JAX-RPC ServiceRefBuilders registered");
165 } else {
166 jaxrpcBuilder = (ServiceRefBuilder) this.jaxrpcBuilders.iterator()
167 .next();
168 }
169 return jaxrpcBuilder;
170 }
171
172 private void mergeEnvironment(Environment environment, ServiceRefBuilder builder) {
173 Environment env = builder.getEnvironment();
174 if (env != null) {
175 EnvironmentBuilder.mergeEnvironments(environment, env);
176 }
177 }
178
179 private Class loadClass(String name, ClassLoader cl)
180 throws DeploymentException {
181 try {
182 return cl.loadClass(name);
183 } catch (ClassNotFoundException e) {
184 throw new DeploymentException("Could not load service class "
185 + name, e);
186 }
187 }
188
189 private static Map mapServiceRefs(XmlObject[] refs) {
190 Map refMap = new HashMap();
191 if (refs != null) {
192 for (int i = 0; i < refs.length; i++) {
193 GerServiceRefType ref = (GerServiceRefType) refs[i].copy()
194 .changeType(GerServiceRefType.type);
195 String serviceRefName = ref.getServiceRefName().trim();
196 refMap.put(serviceRefName, ref);
197 }
198 }
199 return refMap;
200 }
201
202 private void processAnnotations(Module module) throws DeploymentException {
203
204 // Process all the annotations for this naming builder type
205 //At the moment the only exception thrown is if the resulting doc is not valid. Bail now.
206 try {
207 WebServiceRefAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder());
208 ResourceAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder(), ServiceRefProcessor.INSTANCE);
209 }
210 catch (Exception e) {
211 log.warn("Unable to process @Resource annotations for module" + module.getName(), e);
212 }
213 }
214
215 public QNameSet getSpecQNameSet() {
216 return serviceRefQNameSet;
217 }
218
219 public QNameSet getPlanQNameSet() {
220 return GER_SERVICE_REF_QNAME_SET;
221 }
222
223 public static class ServiceRefProcessor extends ResourceAnnotationHelper.ResourceProcessor {
224
225 public static final ServiceRefProcessor INSTANCE = new ServiceRefProcessor();
226
227 private ServiceRefProcessor() {
228 }
229
230 public boolean processResource(AnnotatedApp annotatedApp, Resource annotation, Class cls, Method method, Field field) {
231 log.debug("processResource( [annotatedApp] " + annotatedApp.toString() + "," + '\n' +
232 "[annotation] " + annotation.toString() + "," + '\n' +
233 "[cls] " + (cls != null ? cls.getName() : null) + "," + '\n' +
234 "[method] " + (method != null ? method.getName() : null) + "," + '\n' +
235 "[field] " + (field != null ? field.getName() : null) + " ): Entry");
236
237 String resourceName = getResourceName(annotation, method, field);
238 String resourceType = getResourceType(annotation, method, field);
239
240 log.debug("processResource(): resourceName: " + resourceName);
241 log.debug("processResource(): resourceType: " + resourceType);
242
243 if (resourceType.equals("javax.xml.rpc.Service") ||
244 resourceType.equals("javax.xml.ws.Service") ||
245 resourceType.equals("javax.jws.WebService")) {
246
247 log.debug("processResource(): <service-ref> found");
248
249 boolean exists = false;
250 ServiceRefType[] serviceRefs = annotatedApp.getServiceRefArray();
251 for (ServiceRefType serviceRef : serviceRefs) {
252 if (serviceRef.getServiceRefName().getStringValue().trim().equals(resourceName)) {
253 if (method != null || field != null) {
254 InjectionTargetType[] targets = serviceRef.getInjectionTargetArray();
255 if (!hasTarget(method, field, targets)) {
256 configureInjectionTarget(serviceRef.addNewInjectionTarget(), method, field);
257 }
258 }
259 exists = true;
260 break;
261 }
262 }
263 if (!exists) {
264 try {
265
266 log.debug("processResource(): Does not exist in DD: " + resourceName);
267
268 // Doesn't exist in deployment descriptor -- add new
269 ServiceRefType serviceRef = annotatedApp.addNewServiceRef();
270
271 //------------------------------------------------------------------------------
272 // <service-ref> required elements:
273 //------------------------------------------------------------------------------
274
275 // service-ref-name
276 JndiNameType serviceRefName = serviceRef.addNewServiceRefName();
277 serviceRefName.setStringValue(resourceName);
278 serviceRef.setServiceRefName(serviceRefName);
279
280 // service-ref-interface
281 FullyQualifiedClassType serviceRefInterfaceClass = serviceRef.addNewServiceInterface();
282 serviceRefInterfaceClass.setStringValue(resourceType);
283 serviceRef.setServiceInterface(serviceRefInterfaceClass);
284
285 //------------------------------------------------------------------------------
286 // <service-ref> optional elements:
287 //------------------------------------------------------------------------------
288
289 // description
290 String descriptionAnnotation = annotation.description();
291 if (!descriptionAnnotation.equals("")) {
292 DescriptionType description = serviceRef.addNewDescription();
293 description.setStringValue(descriptionAnnotation);
294 }
295
296 // service-ref-type
297 if (!serviceRef.isSetServiceRefType()) {
298 FullyQualifiedClassType serviceRefTypeClass = serviceRef.addNewServiceRefType();
299 serviceRefTypeClass.setStringValue(resourceType);
300 serviceRef.setServiceRefType(serviceRefTypeClass);
301 }
302
303 // mappedName
304 if (!serviceRef.isSetMappedName() && annotation.mappedName().trim().length() > 0) {
305 XsdStringType mappedName = serviceRef.addNewMappedName();
306 mappedName.setStringValue(annotation.mappedName().trim());
307 serviceRef.setMappedName(mappedName);
308 }
309 }
310 catch (Exception anyException) {
311 log.debug("SwitchServiceRefBuilder: Exception caught while processing <service-ref>");
312 }
313 }
314 return true;
315 }
316 return false;
317 }
318 }
319
320 public static final GBeanInfo GBEAN_INFO;
321
322 static {
323 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(
324 SwitchingServiceRefBuilder.class, NameFactory.MODULE_BUILDER);
325 infoBuilder.addAttribute("eeNamespaces", String[].class, true, true);
326 infoBuilder.addReference("JAXRPCBuilder", ServiceRefBuilder.class,
327 NameFactory.MODULE_BUILDER);
328 infoBuilder.addReference("JAXWSBuilder", ServiceRefBuilder.class,
329 NameFactory.MODULE_BUILDER);
330
331 infoBuilder.setConstructor(new String[]{"eeNamespaces",
332 "JAXRPCBuilder", "JAXWSBuilder"});
333
334 GBEAN_INFO = infoBuilder.getBeanInfo();
335 }
336
337 public static GBeanInfo getGBeanInfo() {
338 return GBEAN_INFO;
339 }
340 }