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