001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.jaxws.description.impl;
020:
021: /**
022: *
023: */
024:
025: import org.apache.axis2.context.ConfigurationContext;
026: import org.apache.axis2.description.AxisService;
027: import org.apache.axis2.jaxws.ClientConfigurationFactory;
028: import org.apache.axis2.jaxws.ExceptionFactory;
029: import org.apache.axis2.jaxws.description.DescriptionFactory;
030: import org.apache.axis2.jaxws.description.DescriptionKey;
031: import org.apache.axis2.jaxws.description.EndpointDescription;
032: import org.apache.axis2.jaxws.description.ServiceDescription;
033: import org.apache.axis2.jaxws.description.builder.DescriptionBuilderComposite;
034: import org.apache.axis2.jaxws.description.builder.converter.JavaClassToDBCConverter;
035: import org.apache.axis2.jaxws.description.validator.ServiceDescriptionValidator;
036: import org.apache.axis2.jaxws.description.validator.EndpointDescriptionValidator;
037: import org.apache.commons.logging.Log;
038: import org.apache.commons.logging.LogFactory;
039:
040: import javax.xml.namespace.QName;
041: import java.net.URL;
042: import java.util.ArrayList;
043: import java.util.HashMap;
044: import java.util.Hashtable;
045: import java.util.Iterator;
046: import java.util.List;
047: import java.util.Map;
048:
049: /**
050: * Creates the JAX-WS metadata descritpion hierachy from some combinations of WSDL, Java classes
051: * with annotations, and (in the future) deployment descriptors. This is the implementation and is
052: * not intended to be a public API. The API is:
053: *
054: * @see org.apache.axis2.jaxws.description.DescriptionFactory
055: */
056: public class DescriptionFactoryImpl {
057: private static final Log log = LogFactory
058: .getLog(DescriptionFactoryImpl.class);
059: private static ClientConfigurationFactory clientConfigFactory = ClientConfigurationFactory
060: .newInstance();
061: private static Map<DescriptionKey, ServiceDescription> cache = new Hashtable<DescriptionKey, ServiceDescription>();
062:
063: /** A DescrptionFactory can not be instantiated; all methods are static. */
064: private DescriptionFactoryImpl() {
065: }
066:
067: /**
068: * @see org.apache.axis2.jaxws.description.DescriptionFactory#createServiceDescription(URL,
069: * QName, Class)
070: */
071: public static ServiceDescription createServiceDescription(
072: URL wsdlURL, QName serviceQName, Class serviceClass) {
073: ConfigurationContext configContext = DescriptionFactory
074: .createClientConfigurationFactory()
075: .getClientConfigurationContext();
076: DescriptionKey key = new DescriptionKey(serviceQName, wsdlURL,
077: serviceClass, configContext);
078: if (log.isDebugEnabled()) {
079: log.debug("Cache Map = " + cache.toString());
080: if (key != null)
081: log.debug("Description Key = " + key.printKey());
082:
083: }
084: ServiceDescription serviceDesc = null;
085: synchronized (configContext) {
086: serviceDesc = cache.get(key);
087: if (log.isDebugEnabled()) {
088: log
089: .debug("Check to see if ServiceDescription is found in cache");
090: }
091: if (serviceDesc != null) {
092: if (log.isDebugEnabled()) {
093: log.debug("ServiceDescription found in the cache");
094: log.debug(serviceDesc.toString());
095: }
096: }
097: if (serviceDesc == null) {
098: if (log.isDebugEnabled()) {
099: log
100: .debug("ServiceDescription not found in the cache");
101: log.debug(" creating new ServiceDescriptionImpl");
102: }
103:
104: ServiceDescriptionImpl serviceDescImpl = new ServiceDescriptionImpl(
105: wsdlURL, serviceQName, serviceClass);
106: serviceDescImpl.setAxisConfigContext(configContext);
107:
108: serviceDesc = serviceDescImpl;
109: if (log.isDebugEnabled()) {
110: log
111: .debug("ServiceDescription created with WSDL URL: "
112: + wsdlURL
113: + "; QName: "
114: + serviceQName
115: + "; Class: "
116: + serviceClass);
117: log.debug(serviceDesc.toString());
118: }
119: if (log.isDebugEnabled()) {
120: log
121: .debug("Caching new ServiceDescription in the cache");
122: }
123: cache.put(key, serviceDesc);
124: }
125: }
126: return serviceDesc;
127: }
128:
129: /**
130: * Clears the entire ServiceDescription cache.
131: *
132: * <h4>Note</h4>
133: * This function might cause unpredictable results when configuration contexts are being reused
134: * and/or there are outstanding requests using the cached ServiceDescription objects. Also,
135: * in-flight requests (both client and server) using ServiceDelegates MUST be done and out of
136: * scope before this method is called.
137: *
138: */
139: public static void clearServiceDescriptionCache() {
140: cache.clear();
141: }
142:
143: /**
144: * Clears all the ServiceDescription objects in the cache associated with the specified
145: * configuration context.
146: *
147: * <h4>Note</h4>
148: * This function should only be used to clear the cache when the specified configuration context
149: * will not be used anymore and there are no outstanding requests using the associated
150: * ServiceDescription objects. Also, in-flight requests (both client and server) using
151: * ServiceDelegates MUST be done and out of scope before this method is called.
152: * Otherwise, unpredictable results might occur.
153: *
154: * @param configContext The configuration context associated with the ServiceDescription
155: * objects in the cache.
156: */
157: public static void clearServiceDescriptionCache(
158: ConfigurationContext configContext) {
159: if (configContext == null) {
160: return;
161: }
162: synchronized (configContext) {
163: synchronized (cache) {
164: Iterator<DescriptionKey> iter = cache.keySet()
165: .iterator();
166: while (iter.hasNext()) {
167: DescriptionKey key = iter.next();
168: if (key.getConfigContext() == configContext) {
169: iter.remove();
170: }
171: }
172: }
173: }
174: }
175:
176: /**
177: * @see org.apache.axis2.jaxws.description.DescriptionFactory#createServiceDescriptionFromServiceImpl(Class,
178: * AxisService)
179: * @deprecated
180: */
181: public static ServiceDescription createServiceDescriptionFromServiceImpl(
182: Class serviceImplClass, AxisService axisService) {
183: ServiceDescription serviceDesc = new ServiceDescriptionImpl(
184: serviceImplClass, axisService);
185: if (log.isDebugEnabled()) {
186: log
187: .debug("Deprecated method used! ServiceDescription created with Class: "
188: + serviceImplClass
189: + "; AxisService: "
190: + axisService);
191: log.debug(serviceDesc.toString());
192: }
193: return serviceDesc;
194: }
195:
196: /** @see org.apache.axis2.jaxws.description.DescriptionFactory#createServiceDescription(Class) */
197: public static ServiceDescription createServiceDescription(
198: Class serviceImplClass) {
199: ServiceDescription serviceDesc = null;
200:
201: if (serviceImplClass != null) {
202: JavaClassToDBCConverter converter = new JavaClassToDBCConverter(
203: serviceImplClass);
204: HashMap<String, DescriptionBuilderComposite> dbcMap = converter
205: .produceDBC();
206: List<ServiceDescription> serviceDescList = createServiceDescriptionFromDBCMap(dbcMap);
207: if (serviceDescList != null && serviceDescList.size() > 0) {
208: serviceDesc = serviceDescList.get(0);
209: if (log.isDebugEnabled()) {
210: log.debug("ServiceDescription created with class: "
211: + serviceImplClass);
212: log.debug(serviceDesc);
213: }
214: } else {
215: if (log.isDebugEnabled()) {
216: log
217: .debug("ServiceDesciption was not created for class: "
218: + serviceImplClass);
219: }
220: // TODO: NLS & RAS
221: throw ExceptionFactory
222: .makeWebServiceException("A ServiceDescription was not created for "
223: + serviceImplClass);
224: }
225: }
226: return serviceDesc;
227: }
228:
229: /** @see org.apache.axis2.jaxws.description.DescriptionFactory#createServiceDescriptionFromDBCMap(HashMap) */
230: public static List<ServiceDescription> createServiceDescriptionFromDBCMap(
231: HashMap<String, DescriptionBuilderComposite> dbcMap) {
232:
233: List<ServiceDescription> serviceDescriptionList = new ArrayList<ServiceDescription>();
234:
235: for (Iterator<DescriptionBuilderComposite> nameIter = dbcMap
236: .values().iterator(); nameIter.hasNext();) {
237: DescriptionBuilderComposite serviceImplComposite = nameIter
238: .next();
239: if (isImpl(serviceImplComposite)) {
240: // process this impl class
241: ServiceDescription serviceDescription = new ServiceDescriptionImpl(
242: dbcMap, serviceImplComposite);
243: ServiceDescriptionValidator validator = new ServiceDescriptionValidator(
244: serviceDescription);
245: if (validator.validate()) {
246: serviceDescriptionList.add(serviceDescription);
247: if (log.isDebugEnabled()) {
248: log
249: .debug("Service Description created from DescriptionComposite: "
250: + serviceDescription);
251: }
252: } else {
253:
254: String msg = "The ServiceDescription failed to validate due to the following errors: \n"
255: + validator.toString();
256:
257: if (log.isDebugEnabled()) {
258: log.debug("Validation Phase 2 failure: " + msg);
259: log.debug("Failing composite: "
260: + serviceImplComposite.toString());
261: log.debug("Failing Service Description: "
262: + serviceDescription.toString());
263: }
264:
265: // TODO: Validate all service descriptions before failing
266: // TODO: Get more detailed failure information from the Validator
267: throw ExceptionFactory.makeWebServiceException(msg);
268: }
269: } else {
270: if (log.isDebugEnabled()) {
271: log.debug("DBC is not a service impl: "
272: + serviceImplComposite.toString());
273: }
274: }
275: }
276:
277: // TODO: Process all composites that are WebFaults...current thinking is
278: // that
279: // since WebFault annotations only exist on exception classes, then they
280: // should be processed by themselves, and at this level
281:
282: return serviceDescriptionList;
283: }
284:
285: /**
286: * @see org.apache.axis2.jaxws.description.DescriptionFactory#updateEndpoint(ServiceDescription,
287: * Class, QName, org.apache.axis2.jaxws.description.DescriptionFactory.UpdateType)
288: */
289: public static EndpointDescription updateEndpoint(
290: ServiceDescription serviceDescription, Class sei,
291: QName portQName, DescriptionFactory.UpdateType updateType) {
292: EndpointDescription endpointDesc = null;
293: synchronized (serviceDescription) {
294: endpointDesc = ((ServiceDescriptionImpl) serviceDescription)
295: .updateEndpointDescription(sei, portQName,
296: updateType);
297: }
298: EndpointDescriptionValidator endpointValidator = new EndpointDescriptionValidator(
299: endpointDesc);
300:
301: boolean isEndpointValid = endpointValidator.validate();
302:
303: if (!isEndpointValid) {
304: String msg = "The Endpoint description validation failed to validate due to the following errors: \n"
305: + endpointValidator.toString();
306:
307: throw ExceptionFactory.makeWebServiceException(msg);
308: }
309: if (log.isDebugEnabled()) {
310: log.debug("EndpointDescription updated: " + endpointDesc);
311: }
312: return endpointDesc;
313: }
314:
315: public static ClientConfigurationFactory getClientConfigurationFactory() {
316:
317: if (clientConfigFactory == null) {
318: clientConfigFactory = ClientConfigurationFactory
319: .newInstance();
320: }
321: return clientConfigFactory;
322: }
323:
324: /**
325: * Builds a list of DescriptionBuilderComposite which is relevant to the particular class
326: *
327: * @param List<> A list of DescriptionBuilderComposite objects
328: * @param serviceImplName
329: * @return List<>
330: */
331: private static List<DescriptionBuilderComposite> buildRelevantCompositeList(
332: List<DescriptionBuilderComposite> compositeList,
333: String serviceImplName) {
334:
335: List<DescriptionBuilderComposite> relevantList = compositeList;
336:
337: // TODO: Find the composite which represents this serviceImplName
338:
339: // TODO: Go through input list to find composites relevant to this one
340: // and add
341: // to 'relevant list'
342:
343: return relevantList;
344: }
345:
346: /**
347: * This method will be used to determine if a given DBC represents a Web service
348: * implementation.
349: *
350: * @param dbc - <code>DescriptionBuilderComposite</code>
351: * @return - <code>boolean</code>
352: */
353: private static boolean isImpl(DescriptionBuilderComposite dbc) {
354: if (!dbc.isInterface()
355: && (dbc.getWebServiceAnnot() != null || dbc
356: .getWebServiceProviderAnnot() != null)) {
357: return true;
358: }
359: return false;
360: }
361:
362: }
|