001: /*
002: * WSDLParser.java
003: *
004: * Created on September 24, 2006, 4:58 PM
005: *
006: * To change this template, choose Tools | Template Manager
007: * and open the template in the editor.
008: */
009:
010: package org.netbeans.modules.e2e.wsdl;
011:
012: import java.io.IOException;
013: import java.util.ArrayList;
014: import java.util.Collections;
015: import java.util.HashMap;
016: import java.util.List;
017: import java.util.Map;
018: import java.util.Stack;
019: import javax.xml.namespace.QName;
020: import javax.xml.parsers.ParserConfigurationException;
021: import javax.xml.parsers.SAXParser;
022: import javax.xml.parsers.SAXParserFactory;
023: import org.netbeans.modules.e2e.api.schema.SchemaException;
024: import org.netbeans.modules.e2e.api.wsdl.Binding;
025: import org.netbeans.modules.e2e.api.wsdl.BindingFault;
026: import org.netbeans.modules.e2e.api.wsdl.BindingInput;
027: import org.netbeans.modules.e2e.api.wsdl.BindingOperation;
028: import org.netbeans.modules.e2e.api.wsdl.BindingOutput;
029: import org.netbeans.modules.e2e.api.wsdl.Definition;
030: import org.netbeans.modules.e2e.api.wsdl.Fault;
031: import org.netbeans.modules.e2e.api.wsdl.Input;
032: import org.netbeans.modules.e2e.api.wsdl.Message;
033: import org.netbeans.modules.e2e.api.wsdl.Operation;
034: import org.netbeans.modules.e2e.api.wsdl.Output;
035: import org.netbeans.modules.e2e.api.wsdl.Part;
036: import org.netbeans.modules.e2e.api.wsdl.Port;
037: import org.netbeans.modules.e2e.api.wsdl.PortType;
038: import org.netbeans.modules.e2e.api.wsdl.Service;
039: import org.netbeans.modules.e2e.api.wsdl.extensions.soap.SOAPAddress;
040: import org.netbeans.modules.e2e.api.wsdl.extensions.soap.SOAPBinding;
041: import org.netbeans.modules.e2e.api.wsdl.extensions.soap.SOAPBody;
042: import org.netbeans.modules.e2e.api.wsdl.extensions.soap.SOAPFault;
043: import org.netbeans.modules.e2e.api.wsdl.extensions.soap.SOAPHeader;
044: import org.netbeans.modules.e2e.api.wsdl.extensions.soap.SOAPHeaderFault;
045: import org.netbeans.modules.e2e.api.wsdl.extensions.soap.SOAPOperation;
046: import org.netbeans.modules.e2e.api.wsdl.wsdl2java.WSDL2Java;
047: import org.netbeans.modules.e2e.schema.SchemaParser;
048: import org.netbeans.modules.e2e.wsdl.extensions.soap.SOAPAddressImpl;
049: import org.netbeans.modules.e2e.wsdl.extensions.soap.SOAPBindingImpl;
050: import org.netbeans.modules.e2e.wsdl.extensions.soap.SOAPBodyImpl;
051: import org.netbeans.modules.e2e.wsdl.extensions.soap.SOAPConstants;
052: import org.netbeans.modules.e2e.wsdl.extensions.soap.SOAPFaultImpl;
053: import org.netbeans.modules.e2e.wsdl.extensions.soap.SOAPHeaderImpl;
054: import org.netbeans.modules.e2e.wsdl.extensions.soap.SOAPOperationImpl;
055: import org.openide.util.Exceptions;
056: import org.xml.sax.Attributes;
057: import org.xml.sax.SAXException;
058: import org.xml.sax.helpers.DefaultHandler;
059:
060: /**
061: *
062: * @author Michal Skvor
063: */
064: public class WSDLParser extends DefaultHandler {
065:
066: private static final String SCHEMA = "http://www.w3.org/2001/XMLSchema";
067:
068: /* WSDL states */
069: private static final String DEFINITION = "definitions";
070: private static final String MESSAGE = "message";
071: private static final String PART = "part";
072: private static final String SERVICE = "service";
073: private static final String PORT = "port";
074: private static final String PORT_TYPE = "portType";
075: private static final String OPERATION = "operation";
076:
077: private static final String BINDING = "binding";
078: private static final String BINDING_OPERATION = "binding-operation";
079: private static final String BINDING_INPUT = "binding-input";
080: private static final String BINDING_OUTPUT = "binding-output";
081: private static final String BINDING_FAULT = "binding-fault";
082:
083: private static final String INPUT = "input";
084: private static final String OUTPUT = "output";
085: private static final String FAULT = "fault";
086:
087: private List<WSDL2Java.ValidationResult> validationResults;
088:
089: public WSDLParser() {
090: validationResults = new ArrayList<WSDL2Java.ValidationResult>();
091: }
092:
093: public Definition parse(String uri) throws WSDLException {
094: definition = new DefinitionImpl();
095:
096: // DefaultHandler handler = new DefaultHandlerImpl( definition );
097: SchemaParser schemaParser = new SchemaParser();
098:
099: SAXParserFactory spf = SAXParserFactory.newInstance();
100: try {
101: spf.setNamespaceAware(true);
102:
103: SAXParser parser = spf.newSAXParser();
104: parser.parse(uri, this );
105: try {
106: schemaParser.parseLocation(uri);
107: } catch (SchemaException ex) {
108: throw new WSDLException(ex);
109: }
110: } catch (WSDLException e) {
111: validationResults.add(new WSDL2Java.ValidationResult(
112: WSDL2Java.ValidationResult.ErrorLevel.FATAL, e
113: .getMessage()));
114: } catch (SAXException e) {
115: validationResults.add(new WSDL2Java.ValidationResult(
116: WSDL2Java.ValidationResult.ErrorLevel.FATAL,
117: "Error during parsing : " + e.getMessage()));
118: } catch (ParserConfigurationException e) {
119: validationResults.add(new WSDL2Java.ValidationResult(
120: WSDL2Java.ValidationResult.ErrorLevel.FATAL,
121: "Error during parsing : " + e.getMessage()));
122: } catch (IOException e) {
123: validationResults.add(new WSDL2Java.ValidationResult(
124: WSDL2Java.ValidationResult.ErrorLevel.FATAL,
125: "Communication error : " + e.getMessage()));
126: }
127: definition.setSchemaHolder(schemaParser.getSchemaHolder());
128: validationResults.addAll(schemaParser.getValidationResults());
129:
130: return definition;
131: }
132:
133: public List<WSDL2Java.ValidationResult> getValidationResults() {
134: return Collections.unmodifiableList(validationResults);
135: }
136:
137: // private static class DefaultHandlerImpl extends DefaultHandler {
138:
139: private Stack<String> state = new Stack<String>();
140:
141: private Definition definition;
142: private Message message;
143: private Part part;
144: private Service service;
145: private Port port;
146: private PortType portType;
147: private Operation operation;
148: private Input input;
149: private Output output;
150: private Fault fault;
151:
152: private Binding binding;
153: private BindingOperation bindingOperation;
154: private BindingInput bindingInput;
155: private BindingOutput bindingOutput;
156: private BindingFault bindingFault;
157:
158: private Map<String, String> prefixMapping = new HashMap<String, String>();
159: private String targetNamespace;
160:
161: private SOAPAddress soapAddress;
162: private SOAPBinding soapBinding;
163: private SOAPOperation soapOperation;
164: private SOAPBody soapBody;
165: private SOAPHeader soapHeader;
166: private SOAPHeaderFault soapHeaderFault;
167: private SOAPFault soapFault;
168:
169: private String tagString;
170:
171: @Override
172: public void startPrefixMapping(String prefix, String uri)
173: throws SAXException {
174: // System.err.println(" - mapping : " + prefix + " ~ " + uri );
175: prefixMapping.put(prefix, uri);
176: }
177:
178: @Override
179: public void startElement(String uri, String localName,
180: String qName, Attributes attributes) throws SAXException {
181: tagString = "";
182: if (uri.equals(SOAPConstants.SOAP_URI)) {
183: // soap:address
184: if (localName.equals(SOAPConstants.ADDRESS.getLocalPart())
185: & state.peek().equals(PORT)) {
186: soapAddress = new SOAPAddressImpl(attributes
187: .getValue("location"));
188: return;
189: }
190: // soap:binding
191: if (localName.equals(SOAPConstants.BINDING.getLocalPart())
192: && state.peek().equals(BINDING)) {
193: String style = attributes.getValue("style") != null ? attributes
194: .getValue("style")
195: : SOAPConstants.STYLE_DOCUMENT;
196: soapBinding = new SOAPBindingImpl(attributes
197: .getValue("transport"), style);
198: return;
199: }
200: // soap:operation
201: if (localName
202: .equals(SOAPConstants.OPERATION.getLocalPart())
203: && state.peek().equals(BINDING_OPERATION)) {
204: soapOperation = new SOAPOperationImpl();
205: // TODO: validation
206: soapOperation.setSoapActionURI(attributes
207: .getValue("soapAction"));
208: if (attributes.getValue("style") == null
209: && soapBinding == null) {
210: throw new SAXException(new WSDLException(
211: "Missing mandatory SOAP style definition."));
212: }
213: String style = attributes.getValue("style") != null ? attributes
214: .getValue("style")
215: : soapBinding.getStyle();
216: soapOperation.setStyle(style);
217:
218: return;
219: }
220: // soap:body
221: if (localName.equals(SOAPConstants.BODY.getLocalPart())
222: && (state.peek().equals(BINDING_INPUT) || state
223: .peek().equals(BINDING_OUTPUT))) {
224: soapBody = new SOAPBodyImpl(attributes.getValue("use"));
225: // TODO: parse parts
226: // TODO: parse encoding styles
227: soapBody.setNamespaceURI(attributes
228: .getValue("namespace"));
229: return;
230: }
231: // soap:header
232: if (localName.equals(SOAPConstants.HEADER.getLocalPart())
233: && (state.peek().equals(BINDING_INPUT) || state
234: .peek().equals(BINDING_OUTPUT))) {
235: soapHeader = new SOAPHeaderImpl(parseQName(attributes
236: .getValue("message")), attributes
237: .getValue("part"), attributes.getValue("use"));
238: // TODO: parse encoding styles
239: soapHeader.setNamespaceURI(attributes
240: .getValue("namespace"));
241: return;
242: }
243: // soap:headerfault
244: // TODO: soap:headerfault
245: // soap:fault
246: if (localName.equals(SOAPConstants.FAULT.getLocalPart())
247: && state.peek().equals(BINDING_FAULT)) {
248: soapFault = new SOAPFaultImpl(attributes
249: .getValue("name"), attributes.getValue("use"));
250: // TODO: parse encoding style
251: soapFault.setNamespaceURI(attributes
252: .getValue("namespace"));
253: return;
254: }
255: }
256:
257: if (uri.equals(WSDLConstants.WSDL_URI)) {
258: // System.err.println("<" + localName + ">" );
259: if (localName.equals(DEFINITION) && state.empty()) {
260: targetNamespace = attributes
261: .getValue("targetNamespace");
262: definition.setTargetNamespace(targetNamespace);
263: state.push(DEFINITION);
264: return;
265: }
266:
267: // Message
268: if (localName.equals(WSDLConstants.MESSAGE.getLocalPart())
269: && state.peek().equals(DEFINITION)) {
270: state.push(MESSAGE);
271: String name = attributes.getValue("name");
272: message = new MessageImpl(name);
273: return;
274: }
275: // Message Part
276: if (localName.equals(WSDLConstants.PART.getLocalPart())
277: && state.peek().equals(MESSAGE)) {
278: state.push(PART);
279: part = new PartImpl(attributes.getValue("name"),
280: parseQName(attributes.getValue("type")),
281: parseQName(attributes.getValue("element")));
282: return;
283: }
284:
285: // PortType
286: if (localName
287: .equals(WSDLConstants.PORT_TYPE.getLocalPart())
288: && state.peek().equals(DEFINITION)) {
289: state.push(PORT_TYPE);
290: portType = new PortTypeImpl(attributes.getValue("name"));
291: return;
292: }
293: // Operation
294: if (localName
295: .equals(WSDLConstants.OPERATION.getLocalPart())
296: && state.peek().equals(PORT_TYPE)) {
297: state.push(OPERATION);
298: operation = new OperationImpl(attributes
299: .getValue("name"));
300: // TODO: parameterOrder
301: return;
302: }
303: if (localName.equals(WSDLConstants.INPUT.getLocalPart())
304: && state.peek().equals(OPERATION)) {
305: state.push(INPUT);
306: String messageName = parseQName(
307: attributes.getValue("message")).getLocalPart();
308: input = new InputImpl(attributes.getValue("name"),
309: definition.getMessage(messageName));
310: return;
311: }
312: if (localName.equals(WSDLConstants.OUTPUT.getLocalPart())
313: && state.peek().equals(OPERATION)) {
314: state.push(OUTPUT);
315: String messageName = parseQName(
316: attributes.getValue("message")).getLocalPart();
317: output = new OutputImpl(attributes.getValue("name"),
318: definition.getMessage(messageName));
319: return;
320: }
321: // Fault
322: if (localName.equals(WSDLConstants.FAULT.getLocalPart())
323: && state.peek().equals(OPERATION)) {
324: state.push(FAULT);
325: String messageName = attributes.getValue("message");
326: fault = new FaultImpl(attributes.getValue("name"),
327: definition.getMessage(messageName));
328: return;
329: }
330:
331: // Binding
332: if (localName.equals(WSDLConstants.BINDING.getLocalPart())
333: && state.peek().equals(DEFINITION)) {
334: state.push(BINDING);
335: QName typeQName = parseQName(attributes
336: .getValue("type"));
337: binding = new BindingImpl(attributes.getValue("name"));
338: binding.setPortType(definition.getPortType(typeQName
339: .getLocalPart()));
340: return;
341: }
342: // BindingOperation
343: if (localName
344: .equals(WSDLConstants.OPERATION.getLocalPart())
345: && state.peek().equals(BINDING)) {
346: state.push(BINDING_OPERATION);
347: bindingOperation = new BindingOperationImpl(attributes
348: .getValue("name"));
349: return;
350: }
351: if (localName.equals(WSDLConstants.INPUT.getLocalPart())
352: && state.peek().equals(BINDING_OPERATION)) {
353: state.push(BINDING_INPUT);
354: bindingInput = new BindingInputImpl(attributes
355: .getValue("name"));
356: return;
357: }
358: if (localName.equals(WSDLConstants.OUTPUT.getLocalPart())
359: && state.peek().equals(BINDING_OPERATION)) {
360: state.push(BINDING_OUTPUT);
361: bindingOutput = new BindingOutputImpl(attributes
362: .getValue("name"));
363: return;
364: }
365: if (localName.equals(WSDLConstants.FAULT.getLocalPart())
366: && state.peek().equals(BINDING_OPERATION)) {
367: state.push(BINDING_FAULT);
368: bindingFault = new BindingFaultImpl(attributes
369: .getValue("name"));
370: return;
371: }
372:
373: // Service
374: if (localName.equals(WSDLConstants.SERVICE.getLocalPart())
375: && state.peek().equals(DEFINITION)) {
376: state.push(SERVICE);
377: service = new ServiceImpl(attributes.getValue("name"));
378: return;
379: }
380: // Port
381: if (localName.equals(WSDLConstants.PORT.getLocalPart())
382: && state.peek().equals(SERVICE)) {
383: state.push(PORT);
384: Binding b = definition.getBinding(parseQName(
385: attributes.getValue("binding")).getLocalPart());
386: // TODO: check for null
387: port = new PortImpl(attributes.getValue("name"), b);
388: return;
389: }
390: // Import
391: if (localName.equals(WSDLConstants.IMPORT.getLocalPart())
392: && state.peek().equals(DEFINITION)) {
393: try {
394: String namespace = attributes.getValue("namespace");
395: String location = attributes.getValue("location");
396: WSDLParser parser = new WSDLParser();
397: Definition d = parser.parse(location);
398:
399: for (Binding b : d.getBindings().values())
400: definition.addBinding(b);
401: for (Message m : d.getMessages().values())
402: definition.addMessage(m);
403: for (Service s : d.getServices().values())
404: definition.addService(s);
405: for (PortType pt : d.getPortTypes().values())
406: definition.addPortType(pt);
407: if (d.getSchemaHolder() != null) {
408: definition.setSchemaHolder(d.getSchemaHolder());
409: }
410:
411: validationResults.addAll(parser
412: .getValidationResults());
413: return;
414: } catch (WSDLException e) {
415: Exceptions.printStackTrace(e);
416: }
417: }
418: }
419: }
420:
421: @Override
422: public void endElement(String uri, String localName, String qName)
423: throws SAXException {
424: if (uri.equals(SOAPConstants.SOAP_URI)) {
425: // soap:address
426: if (localName.equals(SOAPConstants.ADDRESS.getLocalPart())
427: & state.peek().equals(PORT)) {
428: port.addExtensibilityElement(soapAddress);
429: return;
430: }
431: // soap:binding
432: if (localName.equals(SOAPConstants.BINDING.getLocalPart())
433: && state.peek().equals(BINDING)) {
434: binding.addExtensibilityElement(soapBinding);
435: return;
436: }
437: // soap:operation
438: if (localName
439: .equals(SOAPConstants.OPERATION.getLocalPart())
440: && state.peek().equals(BINDING_OPERATION)) {
441: // TODO: validation
442: bindingOperation.addExtensibilityElement(soapOperation);
443: return;
444: }
445: // soap:body
446: if (localName.equals(SOAPConstants.BODY.getLocalPart())) {
447: if (state.peek().equals(BINDING_INPUT)) {
448: bindingInput.addExtensibilityElement(soapBody);
449: }
450: if (state.peek().equals(BINDING_OUTPUT)) {
451: bindingOutput.addExtensibilityElement(soapBody);
452: }
453: return;
454: }
455: // soap:header
456: if (localName.equals(SOAPConstants.HEADER.getLocalPart())) {
457: if (state.peek().equals(BINDING_INPUT)) {
458: bindingInput.addExtensibilityElement(soapHeader);
459: }
460: if (state.peek().equals(BINDING_OUTPUT)) {
461: bindingOutput.addExtensibilityElement(soapHeader);
462: }
463: return;
464: }
465: // soap:headerfault
466: // TODO: header fault
467: // soap:fault
468: if (localName.equals(SOAPConstants.FAULT.getLocalPart())
469: && state.peek().equals(BINDING_FAULT)) {
470: bindingFault.addExtensibilityElement(soapFault);
471: return;
472: }
473: }
474:
475: if (uri.equals(WSDLConstants.WSDL_URI)) {
476: // System.err.println("</" + localName + ">" );
477: if (localName.equals(WSDLConstants.DEFINITIONS
478: .getLocalPart())
479: && state.peek().equals(DEFINITION)) {
480: state.pop();
481: return;
482: }
483:
484: // Message
485: if (localName.equals(WSDLConstants.MESSAGE.getLocalPart())
486: && state.peek().equals(MESSAGE)) {
487: state.pop();
488: definition.addMessage(message);
489: return;
490: }
491: // Message Part
492: if (localName.equals(WSDLConstants.PART.getLocalPart())
493: && state.peek().equals(PART)) {
494: state.pop();
495: message.addPart(part);
496: return;
497: }
498:
499: // PortType
500: if (localName
501: .equals(WSDLConstants.PORT_TYPE.getLocalPart())
502: && state.peek().equals(PORT_TYPE)) {
503: state.pop();
504: definition.addPortType(portType);
505: return;
506: }
507: // Operation
508: if (localName
509: .equals(WSDLConstants.OPERATION.getLocalPart())
510: && state.peek().equals(OPERATION)) {
511: state.pop();
512: portType.addOperation(operation);
513: return;
514: }
515: // Input
516: if (localName.equals(WSDLConstants.INPUT.getLocalPart())
517: && state.peek().equals(INPUT)) {
518: state.pop();
519: operation.setInput(input);
520: return;
521: }
522: // Output
523: if (localName.equals(WSDLConstants.OUTPUT.getLocalPart())
524: && state.peek().equals(OUTPUT)) {
525: state.pop();
526: operation.setOutput(output);
527: return;
528: }
529: // Fault
530: if (localName.equals(WSDLConstants.FAULT.getLocalPart())
531: && state.peek().equals(FAULT)) {
532: state.pop();
533: operation.addFault(fault);
534: return;
535: }
536:
537: // Binding
538: if (localName.equals(WSDLConstants.BINDING.getLocalPart())
539: && state.peek().equals(BINDING)) {
540: state.pop();
541: definition.addBinding(binding);
542: return;
543: }
544: // BindingOperation
545: if (localName
546: .equals(WSDLConstants.OPERATION.getLocalPart())
547: && state.peek().equals(BINDING_OPERATION)) {
548: state.pop();
549: binding.addBindingOperation(bindingOperation);
550: return;
551: }
552: // BindingInput
553: if (localName.equals(WSDLConstants.INPUT.getLocalPart())
554: && state.peek().equals(BINDING_INPUT)) {
555: state.pop();
556: bindingOperation.setBindingInput(bindingInput);
557: return;
558: }
559: // BindingOutput
560: if (localName.equals(WSDLConstants.OUTPUT.getLocalPart())
561: && state.peek().equals(BINDING_OUTPUT)) {
562: state.pop();
563: bindingOperation.setBindingOutput(bindingOutput);
564: return;
565: }
566: // BindingFault
567: if (localName.equals(WSDLConstants.FAULT.getLocalPart())
568: && state.peek().equals(BINDING_FAULT)) {
569: state.pop();
570: bindingOperation.addBindingFault(bindingFault);
571: return;
572: }
573:
574: // Service
575: if (localName.equals(WSDLConstants.SERVICE.getLocalPart())
576: && state.peek().equals(SERVICE)) {
577: state.pop();
578: definition.addService(service);
579: return;
580: }
581: // Port
582: if (localName.equals(WSDLConstants.PORT.getLocalPart())
583: && state.peek().equals(PORT)) {
584: state.pop();
585: service.addPort(port);
586: return;
587: }
588:
589: if (localName.equals(WSDLConstants.DOCUMENTATION
590: .getLocalPart())) {
591: if (state.peek().equals(OPERATION)) {
592: operation.setDocumentation(tagString);
593: }
594: return;
595: }
596: }
597: }
598:
599: public QName parseQName(String qName) {
600: if (qName == null)
601: return null;
602: int colonPos = qName.indexOf(':');
603: if (colonPos > 0) {
604: String prefix = qName.substring(0, colonPos);
605: String uri = prefixMapping.get(prefix);
606: return new QName(uri, qName.substring(colonPos + 1), prefix);
607: }
608: return new QName(targetNamespace, qName);
609: }
610:
611: @Override
612: public void characters(char[] ch, int start, int length)
613: throws SAXException {
614: tagString += new String(ch, start, length);
615: }
616:
617: // private class WSDLException extends Exception {
618: //
619: // public WSDLException( String message ) {
620: // super( message );
621: // }
622: // }
623:
624: // }
625: }
|