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 HandlerChainAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder());
209 ResourceAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder(), ServiceRefProcessor.INSTANCE);
210 }
211 catch (Exception e) {
212 log.warn("Unable to process @Resource annotations for module" + module.getName(), e);
213 }
214 }
215
216 public QNameSet getSpecQNameSet() {
217 return serviceRefQNameSet;
218 }
219
220 public QNameSet getPlanQNameSet() {
221 return GER_SERVICE_REF_QNAME_SET;
222 }
223
224 public static class ServiceRefProcessor extends ResourceAnnotationHelper.ResourceProcessor {
225
226 public static final ServiceRefProcessor INSTANCE = new ServiceRefProcessor();
227
228 private ServiceRefProcessor() {
229 }
230
231 public boolean processResource(AnnotatedApp annotatedApp, Resource annotation, Class cls, Method method, Field field) {
232 log.debug("processResource( [annotatedApp] " + annotatedApp.toString() + "," + '\n' +
233 "[annotation] " + annotation.toString() + "," + '\n' +
234 "[cls] " + (cls != null ? cls.getName() : null) + "," + '\n' +
235 "[method] " + (method != null ? method.getName() : null) + "," + '\n' +
236 "[field] " + (field != null ? field.getName() : null) + " ): Entry");
237
238 String resourceName = getResourceName(annotation, method, field);
239 String resourceType = getResourceType(annotation, method, field);
240
241 log.debug("processResource(): resourceName: " + resourceName);
242 log.debug("processResource(): resourceType: " + resourceType);
243
244 if (resourceType.equals("javax.xml.rpc.Service") ||
245 resourceType.equals("javax.xml.ws.Service") ||
246 resourceType.equals("javax.jws.WebService")) {
247
248 log.debug("processResource(): <service-ref> found");
249
250 boolean exists = false;
251 ServiceRefType[] serviceRefs = annotatedApp.getServiceRefArray();
252 for (ServiceRefType serviceRef : serviceRefs) {
253 if (serviceRef.getServiceRefName().getStringValue().trim().equals(resourceName)) {
254 if (method != null || field != null) {
255 InjectionTargetType[] targets = serviceRef.getInjectionTargetArray();
256 if (!hasTarget(method, field, targets)) {
257 configureInjectionTarget(serviceRef.addNewInjectionTarget(), method, field);
258 }
259 }
260 exists = true;
261 break;
262 }
263 }
264 if (!exists) {
265 try {
266
267 log.debug("processResource(): Does not exist in DD: " + resourceName);
268
269 // Doesn't exist in deployment descriptor -- add new
270 ServiceRefType serviceRef = annotatedApp.addNewServiceRef();
271
272 //------------------------------------------------------------------------------
273 // <service-ref> required elements:
274 //------------------------------------------------------------------------------
275
276 // service-ref-name
277 JndiNameType serviceRefName = serviceRef.addNewServiceRefName();
278 serviceRefName.setStringValue(resourceName);
279 serviceRef.setServiceRefName(serviceRefName);
280
281 // service-ref-interface
282 FullyQualifiedClassType serviceRefInterfaceClass = serviceRef.addNewServiceInterface();
283 serviceRefInterfaceClass.setStringValue(resourceType);
284 serviceRef.setServiceInterface(serviceRefInterfaceClass);
285
286 //------------------------------------------------------------------------------
287 // <service-ref> optional elements:
288 //------------------------------------------------------------------------------
289
290 // description
291 String descriptionAnnotation = annotation.description();
292 if (!descriptionAnnotation.equals("")) {
293 DescriptionType description = serviceRef.addNewDescription();
294 description.setStringValue(descriptionAnnotation);
295 }
296
297 // service-ref-type
298 if (!serviceRef.isSetServiceRefType()) {
299 FullyQualifiedClassType serviceRefTypeClass = serviceRef.addNewServiceRefType();
300 serviceRefTypeClass.setStringValue(resourceType);
301 serviceRef.setServiceRefType(serviceRefTypeClass);
302 }
303
304 // mappedName
305 if (!serviceRef.isSetMappedName() && annotation.mappedName().trim().length() > 0) {
306 XsdStringType mappedName = serviceRef.addNewMappedName();
307 mappedName.setStringValue(annotation.mappedName().trim());
308 serviceRef.setMappedName(mappedName);
309 }
310 }
311 catch (Exception anyException) {
312 log.debug("SwitchServiceRefBuilder: Exception caught while processing <service-ref>");
313 }
314 }
315 return true;
316 }
317 return false;
318 }
319 }
320
321 public static final GBeanInfo GBEAN_INFO;
322
323 static {
324 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(
325 SwitchingServiceRefBuilder.class, NameFactory.MODULE_BUILDER);
326 infoBuilder.addAttribute("eeNamespaces", String[].class, true, true);
327 infoBuilder.addReference("JAXRPCBuilder", ServiceRefBuilder.class,
328 NameFactory.MODULE_BUILDER);
329 infoBuilder.addReference("JAXWSBuilder", ServiceRefBuilder.class,
330 NameFactory.MODULE_BUILDER);
331
332 infoBuilder.setConstructor(new String[]{"eeNamespaces",
333 "JAXRPCBuilder", "JAXWSBuilder"});
334
335 GBEAN_INFO = infoBuilder.getBeanInfo();
336 }
337
338 public static GBeanInfo getGBeanInfo() {
339 return GBEAN_INFO;
340 }
341 }