View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.xml.internal.ws.transport.http;
27  
28  import com.oracle.webservices.internal.api.databinding.DatabindingModeFeature;
29  import com.oracle.webservices.internal.api.databinding.ExternalMetadataFeature;
30  import com.sun.istack.internal.NotNull;
31  import com.sun.xml.internal.ws.api.BindingID;
32  import com.sun.xml.internal.ws.api.WSBinding;
33  import com.sun.xml.internal.ws.api.databinding.MetadataReader;
34  import com.sun.xml.internal.ws.api.server.Container;
35  import com.sun.xml.internal.ws.api.server.SDDocumentSource;
36  import com.sun.xml.internal.ws.api.server.WSEndpoint;
37  import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
38  import com.sun.xml.internal.ws.binding.WebServiceFeatureList;
39  
40  import com.sun.xml.internal.ws.handler.HandlerChainsModel;
41  import com.sun.xml.internal.ws.resources.ServerMessages;
42  import com.sun.xml.internal.ws.resources.WsservletMessages;
43  import com.sun.xml.internal.ws.server.EndpointFactory;
44  import com.sun.xml.internal.ws.server.ServerRtException;
45  import com.sun.xml.internal.ws.streaming.Attributes;
46  import com.sun.xml.internal.ws.streaming.TidyXMLStreamReader;
47  import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
48  import com.sun.xml.internal.ws.util.HandlerAnnotationInfo;
49  import com.sun.xml.internal.ws.util.exception.LocatableWebServiceException;
50  import com.sun.xml.internal.ws.util.xml.XmlUtil;
51  import org.xml.sax.EntityResolver;
52  
53  import javax.xml.namespace.QName;
54  import javax.xml.stream.XMLStreamConstants;
55  import javax.xml.stream.XMLStreamException;
56  import javax.xml.stream.XMLStreamReader;
57  import javax.xml.ws.WebServiceException;
58  import javax.xml.ws.WebServiceFeature;
59  import javax.xml.ws.http.HTTPBinding;
60  import javax.xml.ws.soap.MTOMFeature;
61  import javax.xml.ws.soap.SOAPBinding;
62  import java.io.File;
63  import java.io.FileInputStream;
64  import java.io.IOException;
65  import java.io.InputStream;
66  import java.net.MalformedURLException;
67  import java.net.URL;
68  import java.util.ArrayList;
69  import java.util.Arrays;
70  import java.util.HashMap;
71  import java.util.HashSet;
72  import java.util.List;
73  import java.util.Map;
74  import java.util.Set;
75  import java.util.logging.Level;
76  import java.util.logging.Logger;
77  
78  /**
79   * Parses {@code sun-jaxws.xml} into {@link WSEndpoint}.
80   * <p/>
81   * <p/>
82   * Since {@code sun-jaxws.xml} captures more information than what {@link WSEndpoint}
83   * represents (in particular URL pattern and name), this class
84   * takes a parameterization 'A' so that the user of this parser can choose to
85   * create another type that wraps {@link WSEndpoint}.
86   * <p/>
87   * {@link HttpAdapter} and its derived type is used for this often,
88   * but it can be anything.
89   *
90   * @author WS Development Team
91   * @author Kohsuke Kawaguchi
92   */
93  public class DeploymentDescriptorParser<A> {
94  
95      public static final String NS_RUNTIME = "http://java.sun.com/xml/ns/jax-ws/ri/runtime";
96      public static final String JAXWS_WSDL_DD_DIR = "WEB-INF/wsdl";
97  
98      public static final QName QNAME_ENDPOINTS = new QName(NS_RUNTIME, "endpoints");
99      public static final QName QNAME_ENDPOINT = new QName(NS_RUNTIME, "endpoint");
100     public static final QName QNAME_EXT_METADA = new QName(NS_RUNTIME, "external-metadata");
101 
102     public static final String ATTR_FILE = "file";
103     public static final String ATTR_RESOURCE = "resource";
104 
105     public static final String ATTR_VERSION = "version";
106     public static final String ATTR_NAME = "name";
107     public static final String ATTR_IMPLEMENTATION = "implementation";
108     public static final String ATTR_WSDL = "wsdl";
109     public static final String ATTR_SERVICE = "service";
110     public static final String ATTR_PORT = "port";
111     public static final String ATTR_URL_PATTERN = "url-pattern";
112     public static final String ATTR_ENABLE_MTOM = "enable-mtom";
113     public static final String ATTR_MTOM_THRESHOLD_VALUE = "mtom-threshold-value";
114     public static final String ATTR_BINDING = "binding";
115     public static final String ATTR_DATABINDING = "databinding";
116 
117     public static final List<String> ATTRVALUE_SUPPORTED_VERSIONS = Arrays.asList("2.0", "2.1");
118 
119     private static final Logger logger = Logger.getLogger(com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".server.http");
120 
121     private final Container container;
122     private final ClassLoader classLoader;
123     private final ResourceLoader loader;
124     private final AdapterFactory<A> adapterFactory;
125 
126     /**
127      * Endpoint names that are declared.
128      * Used to catch double definitions.
129      */
130     private final Set<String> names = new HashSet<String>();
131 
132     /**
133      * WSDL/schema documents collected from /WEB-INF/wsdl. Keyed by the system ID.
134      */
135     private final Map<String, SDDocumentSource> docs = new HashMap<String, SDDocumentSource>();
136 
137     /**
138      * @param cl             Used to load service implementations.
139      * @param loader         Used to locate resources, in particular WSDL.
140      * @param container      Optional {@link Container} that {@link WSEndpoint}s receive.
141      * @param adapterFactory Creates {@link HttpAdapter} (or its derived class.)
142      */
143     public DeploymentDescriptorParser(ClassLoader cl, ResourceLoader loader, Container container,
144                                       AdapterFactory<A> adapterFactory) throws MalformedURLException {
145         classLoader = cl;
146         this.loader = loader;
147         this.container = container;
148         this.adapterFactory = adapterFactory;
149 
150         collectDocs("/WEB-INF/wsdl/");
151         logger.log(Level.FINE, "war metadata={0}", docs);
152     }
153 
154     /**
155      * Parses the {@code sun-jaxws.xml} file and configures
156      * a set of {@link HttpAdapter}s.
157      */
158     public @NotNull List<A> parse(String systemId, InputStream is) {
159         XMLStreamReader reader = null;
160         try {
161             reader = new TidyXMLStreamReader(
162                     XMLStreamReaderFactory.create(systemId, is, true), is);
163             XMLStreamReaderUtil.nextElementContent(reader);
164             return parseAdapters(reader);
165         } finally {
166             if (reader != null) {
167                 try {
168                     reader.close();
169                 } catch (XMLStreamException e) {
170                     throw new ServerRtException("runtime.parser.xmlReader", e);
171                 }
172             }
173             try {
174                 is.close();
175             } catch (IOException e) {
176                 // ignore
177             }
178         }
179     }
180 
181     /**
182      * Parses the {@code sun-jaxws.xml} file and configures
183      * a set of {@link HttpAdapter}s.
184      */
185     public @NotNull List<A> parse(File f) throws IOException {
186         FileInputStream in = new FileInputStream(f);
187         try {
188             return parse(f.getPath(), in);
189         } finally {
190             in.close();
191         }
192     }
193 
194     /**
195      * Get all the WSDL & schema documents recursively.
196      */
197     private void collectDocs(String dirPath) throws MalformedURLException {
198         Set<String> paths = loader.getResourcePaths(dirPath);
199         if (paths != null) {
200             for (String path : paths) {
201                 if (path.endsWith("/")) {
202                     if (path.endsWith("/CVS/") || path.endsWith("/.svn/")) {
203                         continue;
204                     }
205                     collectDocs(path);
206                 } else {
207                     URL res = loader.getResource(path);
208                     docs.put(res.toString(), SDDocumentSource.create(res));
209                 }
210             }
211         }
212     }
213 
214 
215     private List<A> parseAdapters(XMLStreamReader reader) {
216         if (!reader.getName().equals(QNAME_ENDPOINTS)) {
217             failWithFullName("runtime.parser.invalidElement", reader);
218         }
219 
220         List<A> adapters = new ArrayList<A>();
221 
222         Attributes attrs = XMLStreamReaderUtil.getAttributes(reader);
223         String version = getMandatoryNonEmptyAttribute(reader, attrs, ATTR_VERSION);
224         if (!ATTRVALUE_SUPPORTED_VERSIONS.contains(version)) {
225             failWithLocalName("runtime.parser.invalidVersionNumber", reader, version);
226         }
227 
228         while (XMLStreamReaderUtil.nextElementContent(reader) != XMLStreamConstants.END_ELEMENT) {
229 
230             if (reader.getName().equals(QNAME_ENDPOINT)) {
231                 attrs = XMLStreamReaderUtil.getAttributes(reader);
232 
233                 String name = getMandatoryNonEmptyAttribute(reader, attrs, ATTR_NAME);
234                 if (!names.add(name)) {
235                     logger.warning(
236                             WsservletMessages.SERVLET_WARNING_DUPLICATE_ENDPOINT_NAME(/*name*/));
237                 }
238 
239                 String implementationName =
240                         getMandatoryNonEmptyAttribute(reader, attrs, ATTR_IMPLEMENTATION);
241                 Class<?> implementorClass = getImplementorClass(implementationName, reader);
242 
243                 MetadataReader metadataReader = null;
244                 ExternalMetadataFeature externalMetadataFeature = null;
245 
246                 // parse subelements to instantiate externalMetadataReader, if necessary ...
247                 XMLStreamReaderUtil.nextElementContent(reader);
248                 if (reader.getEventType() != XMLStreamConstants.END_ELEMENT) {
249                     externalMetadataFeature = configureExternalMetadataReader(reader);
250                     if (externalMetadataFeature != null) {
251                         metadataReader = externalMetadataFeature.getMetadataReader(implementorClass.getClassLoader(), false);
252                     }
253                 }
254 
255                 QName serviceName = getQNameAttribute(attrs, ATTR_SERVICE);
256                 if (serviceName == null) {
257                     serviceName = EndpointFactory.getDefaultServiceName(implementorClass, metadataReader);
258                 }
259 
260                 QName portName = getQNameAttribute(attrs, ATTR_PORT);
261                 if (portName == null) {
262                     portName = EndpointFactory.getDefaultPortName(serviceName, implementorClass, metadataReader);
263                 }
264 
265                 //get enable-mtom attribute value
266                 String enable_mtom = getAttribute(attrs, ATTR_ENABLE_MTOM);
267                 String mtomThreshold = getAttribute(attrs, ATTR_MTOM_THRESHOLD_VALUE);
268                 String dbMode = getAttribute(attrs, ATTR_DATABINDING);
269                 String bindingId = getAttribute(attrs, ATTR_BINDING);
270                 if (bindingId != null) {
271                     // Convert short-form tokens to API's binding ids
272                     bindingId = getBindingIdForToken(bindingId);
273                 }
274                 WSBinding binding = createBinding(bindingId, implementorClass, enable_mtom, mtomThreshold, dbMode);
275                 if (externalMetadataFeature != null) {
276                         binding.getFeatures().mergeFeatures(new WebServiceFeature[]{externalMetadataFeature},
277                         true);
278                 }
279 
280                 String urlPattern = getMandatoryNonEmptyAttribute(reader, attrs, ATTR_URL_PATTERN);
281 
282                 // TODO use 'docs' as the metadata. If wsdl is non-null it's the primary.
283                 boolean handlersSetInDD = setHandlersAndRoles(binding, reader, serviceName, portName);
284 
285                 EndpointFactory.verifyImplementorClass(implementorClass, metadataReader);
286                 SDDocumentSource primaryWSDL = getPrimaryWSDL(reader, attrs, implementorClass, metadataReader);
287 
288                 WSEndpoint<?> endpoint = WSEndpoint.create(
289                         implementorClass, !handlersSetInDD,
290                         null,
291                         serviceName, portName, container, binding,
292                         primaryWSDL, docs.values(), createEntityResolver(), false
293                 );
294                 adapters.add(adapterFactory.createAdapter(name, urlPattern, endpoint));
295             } else {
296                 failWithLocalName("runtime.parser.invalidElement", reader);
297             }
298         }
299         return adapters;
300     }
301 
302     /**
303      * @param ddBindingId   binding id explicitlyspecified in the DeploymentDescriptor or parameter
304      * @param implClass     Endpoint Implementation class
305      * @param mtomEnabled   represents mtom-enabled attribute in DD
306      * @param mtomThreshold threshold value specified in DD
307      * @return is returned with only MTOMFeature set resolving the various precendece rules
308      */
309     private static WSBinding createBinding(String ddBindingId, Class implClass,
310                                            String mtomEnabled, String mtomThreshold, String dataBindingMode) {
311         // Features specified through DD
312         WebServiceFeatureList features;
313 
314         MTOMFeature mtomfeature = null;
315         if (mtomEnabled != null) {
316             if (mtomThreshold != null) {
317                 mtomfeature = new MTOMFeature(Boolean.valueOf(mtomEnabled),
318                         Integer.valueOf(mtomThreshold));
319             } else {
320                 mtomfeature = new MTOMFeature(Boolean.valueOf(mtomEnabled));
321             }
322         }
323 
324         BindingID bindingID;
325         if (ddBindingId != null) {
326             bindingID = BindingID.parse(ddBindingId);
327             features = bindingID.createBuiltinFeatureList();
328 
329             if (checkMtomConflict(features.get(MTOMFeature.class), mtomfeature)) {
330                 throw new ServerRtException(ServerMessages.DD_MTOM_CONFLICT(ddBindingId, mtomEnabled));
331             }
332         } else {
333             bindingID = BindingID.parse(implClass);
334             // Since bindingID is coming from implclass,
335             // mtom through Feature annotation or DD takes precendece
336 
337             features = new WebServiceFeatureList();
338             if (mtomfeature != null) {  // this wins over MTOM setting in bindingID
339                 features.add(mtomfeature);
340             }
341             features.addAll(bindingID.createBuiltinFeatureList());
342         }
343 
344         if (dataBindingMode != null) {
345             features.add(new DatabindingModeFeature(dataBindingMode));
346         }
347 
348         return bindingID.createBinding(features.toArray());
349     }
350 
351     private static boolean checkMtomConflict(MTOMFeature lhs, MTOMFeature rhs) {
352         if (lhs == null || rhs == null) {
353             return false;
354         }
355         return lhs.isEnabled() ^ rhs.isEnabled();
356     }
357 
358     /**
359      * JSR-109 defines short-form tokens for standard binding Ids. These are
360      * used only in DD. So stand alone deployment descirptor should also honor
361      * these tokens. This method converts the tokens to API's standard
362      * binding ids
363      *
364      * @param lexical binding attribute value from DD. Always not null
365      * @return returns corresponding API's binding ID or the same lexical
366      */
367     public static @NotNull String getBindingIdForToken(@NotNull String lexical) {
368         if (lexical.equals("##SOAP11_HTTP")) {
369             return SOAPBinding.SOAP11HTTP_BINDING;
370         } else if (lexical.equals("##SOAP11_HTTP_MTOM")) {
371             return SOAPBinding.SOAP11HTTP_MTOM_BINDING;
372         } else if (lexical.equals("##SOAP12_HTTP")) {
373             return SOAPBinding.SOAP12HTTP_BINDING;
374         } else if (lexical.equals("##SOAP12_HTTP_MTOM")) {
375             return SOAPBinding.SOAP12HTTP_MTOM_BINDING;
376         } else if (lexical.equals("##XML_HTTP")) {
377             return HTTPBinding.HTTP_BINDING;
378         }
379         return lexical;
380     }
381 
382     /**
383      * Creates a new "Adapter".
384      * <p/>
385      * Normally 'A' would be {@link HttpAdapter} or some derived class.
386      * But the parser doesn't require that to be of any particular type.
387      */
388     public static interface AdapterFactory<A> {
389         A createAdapter(String name, String urlPattern, WSEndpoint<?> endpoint);
390     }
391 
392     /**
393      * Checks the deployment descriptor or {@link @WebServiceProvider} annotation
394      * to see if it points to any WSDL. If so, returns the {@link SDDocumentSource}.
395      *
396      * @return The pointed WSDL, if any. Otherwise null.
397      */
398     private SDDocumentSource getPrimaryWSDL(XMLStreamReader xsr, Attributes attrs, Class<?> implementorClass, MetadataReader metadataReader) {
399 
400         String wsdlFile = getAttribute(attrs, ATTR_WSDL);
401         if (wsdlFile == null) {
402             wsdlFile = EndpointFactory.getWsdlLocation(implementorClass, metadataReader);
403         }
404 
405         if (wsdlFile != null) {
406             if (!wsdlFile.startsWith(JAXWS_WSDL_DD_DIR)) {
407                 logger.log(Level.WARNING, "Ignoring wrong wsdl={0}. It should start with {1}. Going to generate and publish a new WSDL.", new Object[]{wsdlFile, JAXWS_WSDL_DD_DIR});
408                 return null;
409             }
410 
411             URL wsdl;
412             try {
413                 wsdl = loader.getResource('/' + wsdlFile);
414             } catch (MalformedURLException e) {
415                 throw new LocatableWebServiceException(
416                         ServerMessages.RUNTIME_PARSER_WSDL_NOT_FOUND(wsdlFile), e, xsr);
417             }
418             if (wsdl == null) {
419                 throw new LocatableWebServiceException(
420                         ServerMessages.RUNTIME_PARSER_WSDL_NOT_FOUND(wsdlFile), xsr);
421             }
422             SDDocumentSource docInfo = docs.get(wsdl.toExternalForm());
423             assert docInfo != null;
424             return docInfo;
425         }
426 
427         return null;
428     }
429 
430     /**
431      * Creates an {@link EntityResolver} that consults {@code /WEB-INF/jax-ws-catalog.xml}.
432      */
433     private EntityResolver createEntityResolver() {
434         try {
435             return XmlUtil.createEntityResolver(loader.getCatalogFile());
436         } catch (MalformedURLException e) {
437             throw new WebServiceException(e);
438         }
439     }
440 
441     protected String getAttribute(Attributes attrs, String name) {
442         String value = attrs.getValue(name);
443         if (value != null) {
444             value = value.trim();
445         }
446         return value;
447     }
448 
449     protected QName getQNameAttribute(Attributes attrs, String name) {
450         String value = getAttribute(attrs, name);
451         if (value == null || value.equals("")) {
452             return null;
453         } else {
454             return QName.valueOf(value);
455         }
456     }
457 
458     protected String getNonEmptyAttribute(XMLStreamReader reader, Attributes attrs, String name) {
459         String value = getAttribute(attrs, name);
460         if (value != null && value.equals("")) {
461             failWithLocalName(
462                     "runtime.parser.invalidAttributeValue",
463                     reader,
464                     name);
465         }
466         return value;
467     }
468 
469     protected String getMandatoryAttribute(XMLStreamReader reader, Attributes attrs, String name) {
470         String value = getAttribute(attrs, name);
471         if (value == null) {
472             failWithLocalName("runtime.parser.missing.attribute", reader, name);
473         }
474         return value;
475     }
476 
477     protected String getMandatoryNonEmptyAttribute(XMLStreamReader reader, Attributes attributes,
478                                                    String name) {
479         String value = getAttribute(attributes, name);
480         if (value == null) {
481             failWithLocalName("runtime.parser.missing.attribute", reader, name);
482         } else if (value.equals("")) {
483             failWithLocalName(
484                     "runtime.parser.invalidAttributeValue",
485                     reader,
486                     name);
487         }
488         return value;
489     }
490 
491     /**
492      * Parses the handler and role information and sets it
493      * on the {@link WSBinding}.
494      *
495      * @return true if <handler-chains> element present in DD
496      *         false otherwise.
497      */
498     protected boolean setHandlersAndRoles(WSBinding binding, XMLStreamReader reader, QName serviceName, QName portName) {
499 
500         if (reader.getEventType() == XMLStreamConstants.END_ELEMENT ||
501                 !reader.getName().equals(HandlerChainsModel.QNAME_HANDLER_CHAINS)) {
502             return false;
503         }
504 
505         HandlerAnnotationInfo handlerInfo = HandlerChainsModel.parseHandlerFile(
506                 reader, classLoader, serviceName, portName, binding);
507 
508         binding.setHandlerChain(handlerInfo.getHandlers());
509         if (binding instanceof SOAPBinding) {
510             ((SOAPBinding) binding).setRoles(handlerInfo.getRoles());
511         }
512 
513         // move past </handler-chains>
514         XMLStreamReaderUtil.nextContent(reader);
515         return true;
516     }
517 
518     protected ExternalMetadataFeature configureExternalMetadataReader(XMLStreamReader reader) {
519 
520         ExternalMetadataFeature.Builder featureBuilder = null;
521         while (QNAME_EXT_METADA.equals(reader.getName())) {
522 
523             if (reader.getEventType() == XMLStreamConstants.START_ELEMENT) {
524                 Attributes attrs = XMLStreamReaderUtil.getAttributes(reader);
525                 String file = getAttribute(attrs, ATTR_FILE);
526                 if (file != null) {
527                     if (featureBuilder == null) {
528                         featureBuilder = ExternalMetadataFeature.builder();
529                     }
530                     featureBuilder.addFiles(new File(file));
531                 }
532 
533                 String res = getAttribute(attrs, ATTR_RESOURCE);
534                 if (res != null) {
535                     if (featureBuilder == null) {
536                         featureBuilder = ExternalMetadataFeature.builder();
537                     }
538                     featureBuilder.addResources(res);
539                 }
540             }
541 
542             XMLStreamReaderUtil.nextElementContent(reader);
543         }
544 
545         return buildFeature(featureBuilder);
546     }
547 
548     private ExternalMetadataFeature buildFeature(ExternalMetadataFeature.Builder builder) {
549         return builder != null ? builder.build() : null;
550     }
551 
552     protected static void fail(String key, XMLStreamReader reader) {
553         logger.log(Level.SEVERE, "{0}{1}", new Object[]{key, reader.getLocation().getLineNumber()});
554         throw new ServerRtException(
555                 key,
556                 Integer.toString(reader.getLocation().getLineNumber()));
557     }
558 
559     protected static void failWithFullName(String key, XMLStreamReader reader) {
560         throw new ServerRtException(
561                 key,
562                 reader.getLocation().getLineNumber(),
563                 reader.getName());
564     }
565 
566     protected static void failWithLocalName(String key, XMLStreamReader reader) {
567         throw new ServerRtException(
568                 key,
569                 reader.getLocation().getLineNumber(),
570                 reader.getLocalName());
571     }
572 
573     protected static void failWithLocalName(String key, XMLStreamReader reader, String arg) {
574         throw new ServerRtException(
575                 key,
576                 reader.getLocation().getLineNumber(),
577                 reader.getLocalName(),
578                 arg);
579     }
580 
581     protected Class loadClass(String name) {
582         try {
583             return Class.forName(name, true, classLoader);
584         } catch (ClassNotFoundException e) {
585             logger.log(Level.SEVERE, e.getMessage(), e);
586             throw new ServerRtException(
587                     "runtime.parser.classNotFound",
588                     name);
589         }
590     }
591 
592 
593     /**
594      * Loads the class of the given name.
595      *
596      * @param xsr Used to report the source location information if there's any error.
597      */
598     private Class getImplementorClass(String name, XMLStreamReader xsr) {
599         try {
600             return Class.forName(name, true, classLoader);
601         } catch (ClassNotFoundException e) {
602             logger.log(Level.SEVERE, e.getMessage(), e);
603             throw new LocatableWebServiceException(
604                     ServerMessages.RUNTIME_PARSER_CLASS_NOT_FOUND(name), e, xsr);
605         }
606     }
607 
608 }