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.servicemix.cxfbc.interceptors;
019    
020    import java.util.ArrayList;
021    import java.util.Collections;
022    import java.util.HashMap;
023    import java.util.List;
024    import java.util.Map;
025    
026    import javax.xml.XMLConstants;
027    import javax.xml.namespace.NamespaceContext;
028    import javax.xml.namespace.QName;
029    import javax.xml.stream.Location;
030    import javax.xml.stream.XMLStreamException;
031    import javax.xml.stream.XMLStreamReader;
032    
033    import org.apache.cxf.binding.soap.Soap11;
034    import org.apache.cxf.binding.soap.Soap12;
035    import org.apache.cxf.binding.soap.SoapMessage;
036    import org.apache.cxf.binding.soap.model.SoapBindingInfo;
037    import org.apache.cxf.binding.soap.model.SoapHeaderInfo;
038    import org.apache.cxf.endpoint.Endpoint;
039    import org.apache.cxf.helpers.DOMUtils;
040    import org.apache.cxf.interceptor.Fault;
041    import org.apache.cxf.message.Message;
042    import org.apache.cxf.service.model.BindingMessageInfo;
043    import org.apache.cxf.service.model.BindingOperationInfo;
044    import org.apache.cxf.service.model.MessagePartInfo;
045    import org.apache.cxf.staxutils.DepthXMLStreamReader;
046    import org.apache.cxf.staxutils.PartialXMLStreamReader;
047    import org.apache.cxf.staxutils.StaxUtils;
048    import org.apache.servicemix.soap.util.stax.ExtendedXMLStreamReader;
049    import org.apache.servicemix.soap.util.stax.FragmentStreamReader;
050    import org.w3c.dom.Document;
051    import org.w3c.dom.Element;
052    import org.w3c.dom.NamedNodeMap;
053    import org.w3c.dom.Node;
054    
055    
056    public class StaxJbiWrapper implements XMLStreamReader {
057        public static final int STATE_START_DOC = 0;
058        public static final int STATE_START_ELEMENT_WRAPPER = 1;
059        public static final int STATE_START_ELEMENT_PART = 2;
060        public static final int STATE_RUN_PART = 3;
061        public static final int STATE_END_ELEMENT_PART = 4;
062        public static final int STATE_END_ELEMENT_WRAPPER = 5;
063        public static final int STATE_END_DOC = 6;
064    
065        private BindingMessageInfo wsdlMessage;
066        private int state = STATE_START_DOC;
067        private int part = -1;
068        private int reader = -1;
069        private int event = START_DOCUMENT;
070        private List<List<XMLStreamReader>> parts = new ArrayList<List<XMLStreamReader>>();
071        private List<QName> extraPrefixes = new ArrayList<QName>();
072    
073        public StaxJbiWrapper(Message message) {
074            setExtraPrefix((SoapMessage) message);
075            BindingOperationInfo wsdlOperation = getOperation(message);
076            wsdlMessage = !isRequestor(message) ? wsdlOperation.getInput() : wsdlOperation.getOutput();
077            XMLStreamReader xmlReader = message.getContent(XMLStreamReader.class);
078            if (isRequestor(message)) {
079                throw new UnsupportedOperationException();
080            }
081            List<SoapHeaderInfo> headers = wsdlMessage
082                .getExtensors(SoapHeaderInfo.class);
083            if (headers != null && headers.size() > 0) {
084                throw new UnsupportedOperationException();
085            }
086            SoapBindingInfo binding = (SoapBindingInfo) message.getExchange()
087                .get(Endpoint.class).getEndpointInfo().getBinding();
088            String style = binding.getStyle(wsdlOperation.getOperationInfo());
089            if (style == null) {
090                style = binding.getStyle();
091            }
092            int nbBodyParts = 0;
093            for (MessagePartInfo part : wsdlMessage.getMessageParts()) {
094                if (nbBodyParts++ > 0) {
095                    throw new UnsupportedOperationException();
096                }
097                if ("document".equals(style)) {
098                    parts.add(Collections.<XMLStreamReader>singletonList(new FragmentStreamReader(xmlReader)));
099                } else /* rpc-style */ {
100                    throw new UnsupportedOperationException();
101                }
102            }
103        }
104        
105        private void setExtraPrefix(SoapMessage message) {
106            Document savedEnv = (Document) message.getContent(Node.class);
107            if (savedEnv != null) {
108                NamedNodeMap attrs = savedEnv.getFirstChild().getAttributes();
109                Map<String, String> nsMap = message.getEnvelopeNs();
110                if (nsMap == null) {
111                    nsMap = new HashMap<String, String>();
112                }
113                for (int i = 0; i < attrs.getLength(); i++) {
114                    Node node = attrs.item(i);
115                    if (!node.getNodeValue().equals(Soap11.SOAP_NAMESPACE)
116                            && !node.getNodeValue().equals(Soap12.SOAP_NAMESPACE)) {
117                        //set extra prefix
118                        nsMap.put(node.getLocalName(), node.getNodeValue());
119                        if (!node.getNodeValue().equals(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)
120                                && !node.getNodeValue().equals(XMLConstants.W3C_XML_SCHEMA_NS_URI))
121                            extraPrefixes.add(new QName(node.getNodeValue(), "", node.getLocalName()));
122                    }
123                        
124                }
125                if (nsMap.size() > 0) {
126                    message.put("soap.env.ns.map", nsMap);
127                }
128            }
129        }
130    
131    
132        public int getEventType() {
133            return event;
134        }
135    
136        public int next() throws XMLStreamException {
137            switch (state) {
138                case STATE_START_DOC:
139                    state = STATE_START_ELEMENT_WRAPPER;
140                    event = START_ELEMENT;
141                    break;
142                case STATE_START_ELEMENT_WRAPPER:
143                    if (parts.size() > 0) {
144                        state = STATE_START_ELEMENT_PART;
145                        event = START_ELEMENT;
146                        part = 0;
147                        reader = 0;
148                    } else {
149                        state = STATE_END_ELEMENT_WRAPPER;
150                        event = END_ELEMENT;
151                    }
152                    break;
153                case STATE_START_ELEMENT_PART:
154                    if (reader >= parts.get(part).size()) {
155                        state = STATE_END_ELEMENT_PART;
156                        event = END_ELEMENT;
157                    } else {
158                        state = STATE_RUN_PART;
159                        event = parts.get(part).get(reader).next();
160                        if (event == START_DOCUMENT) {
161                            event = parts.get(part).get(reader).next();
162                        }
163                    }
164                    break;
165                case STATE_RUN_PART:
166                    event = parts.get(part).get(reader).next();
167                    if (event == END_DOCUMENT) {
168                        if (++reader >= parts.get(part).size()) {
169                            state = STATE_END_ELEMENT_PART;
170                            event = END_ELEMENT;
171                        } else {
172                            event = parts.get(part).get(reader).next();
173                            if (event == START_DOCUMENT) {
174                                event = parts.get(part).get(reader).next();
175                            }
176                        }
177                    }
178                    break;
179                case STATE_END_ELEMENT_PART:
180                    if (++part >= parts.size()) {
181                        state = STATE_END_ELEMENT_WRAPPER;
182                        event = END_ELEMENT;
183                    } else {
184                        state = STATE_START_ELEMENT_PART;
185                        event = START_ELEMENT;
186                        reader = 0;
187                    }
188                    break;
189                case STATE_END_ELEMENT_WRAPPER:
190                case STATE_END_DOC:
191                    state = STATE_END_DOC;
192                    event = END_DOCUMENT;
193                    break;
194            }
195            return event;
196        }
197    
198        public QName getName() {
199            switch (state) {
200                case STATE_START_ELEMENT_WRAPPER:
201                case STATE_END_ELEMENT_WRAPPER:
202                    return CxfJbiConstants.WSDL11_WRAPPER_MESSAGE;
203                case STATE_START_ELEMENT_PART:
204                case STATE_END_ELEMENT_PART:
205                    return CxfJbiConstants.WSDL11_WRAPPER_PART;
206                case STATE_RUN_PART:
207                    return parts.get(part).get(reader).getName();
208                default:
209                    throw new IllegalStateException();
210            }
211        }
212    
213        public String getLocalName() {
214            switch (state) {
215                case STATE_START_ELEMENT_WRAPPER:
216                case STATE_END_ELEMENT_WRAPPER:
217                    return CxfJbiConstants.WSDL11_WRAPPER_MESSAGE_LOCALNAME;
218                case STATE_START_ELEMENT_PART:
219                case STATE_END_ELEMENT_PART:
220                    return CxfJbiConstants.WSDL11_WRAPPER_PART_LOCALNAME;
221                case STATE_RUN_PART:
222                    return parts.get(part).get(reader).getLocalName();
223                default:
224                    throw new IllegalStateException();
225            }
226        }
227    
228        public String getNamespaceURI() {
229            switch (state) {
230                case STATE_START_ELEMENT_WRAPPER:
231                case STATE_END_ELEMENT_WRAPPER:
232                case STATE_START_ELEMENT_PART:
233                case STATE_END_ELEMENT_PART:
234                    return CxfJbiConstants.WSDL11_WRAPPER_NAMESPACE;
235                case STATE_RUN_PART:
236                    return parts.get(part).get(reader).getNamespaceURI();
237                default:
238                    throw new IllegalStateException();
239            }
240        }
241    
242        public String getPrefix() {
243            switch (state) {
244                case STATE_START_ELEMENT_WRAPPER:
245                case STATE_END_ELEMENT_WRAPPER:
246                case STATE_START_ELEMENT_PART:
247                case STATE_END_ELEMENT_PART:
248                    return CxfJbiConstants.WSDL11_WRAPPER_PREFIX;
249                case STATE_RUN_PART:
250                    String prefix = parts.get(part).get(reader).getPrefix();
251                    String namespaceURI;
252                    if (prefix != null && prefix.length() == 0 
253                            && ((namespaceURI = parts.get(part).get(reader).getNamespaceURI()) != null && namespaceURI.length() > 0)) {
254                        return CxfJbiConstants.WSDL11_WRAPPER_PART_LOCALNAME;
255                    } else {
256                        return prefix;
257                    }
258                default:
259                    throw new IllegalStateException();
260            }
261        }
262    
263        public boolean hasName() {
264            return state == STATE_RUN_PART ? parts.get(part).get(reader).isStartElement() : (event == START_ELEMENT || event == END_ELEMENT);
265        }
266    
267        public Object getProperty(String s) throws IllegalArgumentException {
268            return null;  //To change body of implemented methods use File | Settings | File Templates.
269        }
270    
271        public void require(int i, String s, String s1) throws XMLStreamException {
272            //To change body of implemented methods use File | Settings | File Templates.
273        }
274    
275        public String getElementText() throws XMLStreamException {
276            return null;  //To change body of implemented methods use File | Settings | File Templates.
277        }
278    
279        public int nextTag() throws XMLStreamException {
280            while (hasNext()) {
281                int e = next();
282                if (e == START_ELEMENT || e == END_ELEMENT)
283                    return e;
284            }
285            return event;
286        }
287    
288        public boolean hasNext() throws XMLStreamException {
289            return event != END_DOCUMENT;
290        }
291    
292        public void close() throws XMLStreamException {
293            //To change body of implemented methods use File | Settings | File Templates.
294        }
295    
296        public String getNamespaceURI(String s) {
297            return null;  //To change body of implemented methods use File | Settings | File Templates.
298        }
299    
300        public boolean isStartElement() {
301            return state == STATE_RUN_PART ? parts.get(part).get(reader).isStartElement() : event == START_ELEMENT;
302        }
303    
304        public boolean isEndElement() {
305            return state == STATE_RUN_PART ? parts.get(part).get(reader).isEndElement() : event == END_ELEMENT;
306        }
307    
308        public boolean isCharacters() {
309            return state == STATE_RUN_PART ? parts.get(part).get(reader).isCharacters() : event == CHARACTERS;
310        }
311    
312        public boolean isWhiteSpace() {
313            return state == STATE_RUN_PART ? parts.get(part).get(reader).isWhiteSpace() : event == SPACE;
314        }
315    
316        public String getAttributeValue(String s, String s1) {
317            throw new UnsupportedOperationException("Not implemented");
318        }
319    
320        public int getAttributeCount() {
321            switch (state) {
322                case STATE_START_ELEMENT_WRAPPER:
323                    return 7 + extraPrefixes.size();
324                case STATE_START_ELEMENT_PART:
325                    return 0;
326                case STATE_RUN_PART:
327                    return parts.get(part).get(reader).getAttributeCount();
328                default:
329                    throw new IllegalStateException();
330            }
331        }
332    
333        public QName getAttributeName(int i) {
334            switch (state) {
335                case STATE_START_ELEMENT_WRAPPER:
336                    switch (i) {
337                        case 0: return new QName(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
338                                CxfJbiConstants.WSDL11_WRAPPER_PREFIX,
339                                                XMLConstants.XMLNS_ATTRIBUTE);
340                        case 1: return new QName(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
341                                CxfJbiConstants.WSDL11_WRAPPER_MESSAGE_PREFIX,
342                                                 XMLConstants.XMLNS_ATTRIBUTE);
343                        case 2: return new QName(CxfJbiConstants.WSDL11_WRAPPER_TYPE);
344                        case 3: return new QName(CxfJbiConstants.WSDL11_WRAPPER_NAME);
345                        case 4: return new QName(CxfJbiConstants.WSDL11_WRAPPER_VERSION);
346                        case 5: return new QName(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
347                                CxfJbiConstants.WSDL11_WRAPPER_XSI_PREFIX,
348                                                 XMLConstants.XMLNS_ATTRIBUTE);
349                        case 6: return new QName(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
350                                CxfJbiConstants.WSDL11_WRAPPER_XSD_PREFIX,
351                                                 XMLConstants.XMLNS_ATTRIBUTE);
352                        default:{
353                            if (i < getAttributeCount()) {
354                                return new QName(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
355                                        extraPrefixes.get(i - 7).getPrefix(),
356                                                         XMLConstants.XMLNS_ATTRIBUTE);
357                            } else {
358                                throw new IllegalStateException();
359                            }
360                        }
361                    }
362                case STATE_RUN_PART:
363                    return parts.get(part).get(reader).getAttributeName(i);
364                default:
365                    throw new IllegalStateException();
366            }
367        }
368    
369        public String getAttributeNamespace(int i) {
370            switch (state) {
371                case STATE_START_ELEMENT_WRAPPER:
372                    switch (i) {
373                        case 0:
374                        case 1: return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
375                        case 2:
376                        case 3:
377                        case 4: return XMLConstants.NULL_NS_URI;
378                        case 5: return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
379                        case 6: return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
380                        default: {
381                            if (i < getAttributeCount()) {
382                                return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
383                            } else {
384                                throw new IllegalStateException();
385                            }
386                        }
387                    }
388                case STATE_RUN_PART:
389                    return parts.get(part).get(reader).getAttributeNamespace(i);
390                default:
391                    throw new IllegalStateException();
392            }
393        }
394    
395        public String getAttributeLocalName(int i) {
396            switch (state) {
397                case STATE_START_ELEMENT_WRAPPER:
398                    switch (i) {
399                        case 0: return CxfJbiConstants.WSDL11_WRAPPER_PREFIX; 
400                        case 1: return CxfJbiConstants.WSDL11_WRAPPER_MESSAGE_PREFIX;
401                        case 2: return CxfJbiConstants.WSDL11_WRAPPER_TYPE;
402                        case 3: return CxfJbiConstants.WSDL11_WRAPPER_NAME;
403                        case 4: return CxfJbiConstants.WSDL11_WRAPPER_VERSION;
404                        case 5: return CxfJbiConstants.WSDL11_WRAPPER_XSI_PREFIX;
405                        case 6: return CxfJbiConstants.WSDL11_WRAPPER_XSD_PREFIX;
406                        default: {
407                            if (i < getAttributeCount()) {
408                                return extraPrefixes.get(i -7).getPrefix();
409                            } else {
410                                throw new IllegalStateException();
411                            }
412                        }
413                    }
414                case STATE_RUN_PART:
415                    return parts.get(part).get(reader).getAttributeLocalName(i);
416                default:
417                    throw new IllegalStateException();
418            }
419        }
420    
421        public String getAttributePrefix(int i) {
422            switch (state) {
423                case STATE_START_ELEMENT_WRAPPER:
424                    switch (i) {
425                        case 0: return XMLConstants.XMLNS_ATTRIBUTE;
426                        case 1: return XMLConstants.XMLNS_ATTRIBUTE;
427                        case 2:
428                        case 3:
429                        case 4: return XMLConstants.DEFAULT_NS_PREFIX;
430                        case 5: return XMLConstants.XMLNS_ATTRIBUTE;
431                        case 6: return XMLConstants.XMLNS_ATTRIBUTE;
432                        default: {
433                            if (i < getAttributeCount()) {
434                                return XMLConstants.XMLNS_ATTRIBUTE;
435                            } else {
436                                throw new IllegalStateException();
437                            }
438                        }
439                    }
440                case STATE_RUN_PART:
441                    return parts.get(part).get(reader).getAttributePrefix(i);
442                default:
443                    throw new IllegalStateException();
444            }
445        }
446    
447        public String getAttributeType(int i) {
448            return "CDATA";
449        }
450    
451        public String getAttributeValue(int i) {
452            switch (state) {
453                case STATE_START_ELEMENT_WRAPPER:
454                    switch (i) {
455                        case 0:
456                        {
457                            return CxfJbiConstants.WSDL11_WRAPPER_NAMESPACE;
458                        }
459                        case 1:
460                        {
461                            String typeNamespace = wsdlMessage.getMessageInfo().getName().getNamespaceURI();
462                            if (typeNamespace == null || typeNamespace.length() == 0) {
463                                throw new IllegalArgumentException("messageType namespace is null or empty");
464                            }
465                            return typeNamespace;
466                        }
467                        case 2:
468                        {
469                            String typeLocalName = wsdlMessage.getMessageInfo().getName().getLocalPart();
470                            if (typeLocalName == null || typeLocalName.length() == 0) {
471                                throw new IllegalArgumentException("messageType local name is null or empty");
472                            }
473                            return CxfJbiConstants.WSDL11_WRAPPER_MESSAGE_PREFIX + ":" + typeLocalName;
474                        }
475                        case 3:
476                            return wsdlMessage.getMessageInfo().getName().getLocalPart().toString();
477                        case 4:
478                            return "1.0";
479                        case 5:
480                            return XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI;
481                        case 6:
482                            return XMLConstants.W3C_XML_SCHEMA_NS_URI;
483                        default: {
484                            if (i < getAttributeCount()) {
485                                return extraPrefixes.get(i -7).getNamespaceURI();
486                            } else {
487                                throw new IllegalStateException();
488                            }
489                        }
490                    }
491                case STATE_RUN_PART:
492                    return parts.get(part).get(reader).getAttributeValue(i);
493                default:
494                    throw new IllegalStateException();
495            }
496        }
497    
498        public boolean isAttributeSpecified(int i) {
499            throw new UnsupportedOperationException("Not implemented");
500        }
501    
502        public int getNamespaceCount() {
503            switch (state) {
504            case STATE_START_ELEMENT_WRAPPER:
505            case STATE_END_ELEMENT_WRAPPER:
506            case STATE_START_ELEMENT_PART:
507            case STATE_END_ELEMENT_PART:
508                return 0;
509            case STATE_RUN_PART:
510                return parts.get(part).get(reader).getNamespaceCount();
511            default:
512                throw new IllegalStateException();
513        }
514        }
515    
516        public String getNamespacePrefix(int i) {
517            String prefix = parts.get(part).get(reader).getNamespacePrefix(i);
518            if (prefix != null && prefix.length() == 0 
519                    && parts.get(part).get(reader).getNamespaceURI().length() > 0) {
520                return CxfJbiConstants.WSDL11_WRAPPER_PART_LOCALNAME;
521            } else {
522                return prefix;
523            }
524        }
525    
526        public String getNamespaceURI(int i) {
527            return parts.get(part).get(reader).getNamespaceURI(i);
528        }
529    
530        public NamespaceContext getNamespaceContext() {
531            if (state == STATE_RUN_PART) {
532                return parts.get(part).get(reader).getNamespaceContext();
533            } else {
534                return new ExtendedXMLStreamReader.SimpleNamespaceContext();
535            }
536        }
537    
538        public String getText() {
539            if (state == STATE_RUN_PART) {
540                return parts.get(part).get(reader).getText();
541            } else {
542                throw new IllegalStateException();
543            }
544        }
545    
546        public char[] getTextCharacters() {
547            if (state == STATE_RUN_PART) {
548                return parts.get(part).get(reader).getTextCharacters();
549            } else {
550                throw new IllegalStateException();
551            }
552        }
553    
554        public int getTextCharacters(int i, char[] chars, int i1, int i2) throws XMLStreamException {
555            if (state == STATE_RUN_PART) {
556                return parts.get(part).get(reader).getTextCharacters(i, chars, i1, i2);
557            } else {
558                throw new IllegalStateException();
559            }
560        }
561    
562        public int getTextStart() {
563            if (state == STATE_RUN_PART) {
564                return parts.get(part).get(reader).getTextStart();
565            } else {
566                throw new IllegalStateException();
567            }
568        }
569    
570        public int getTextLength() {
571            if (state == STATE_RUN_PART) {
572                return parts.get(part).get(reader).getTextLength();
573            } else {
574                throw new IllegalStateException();
575            }
576        }
577    
578        public String getEncoding() {
579            throw new UnsupportedOperationException("Not implemented");
580        }
581    
582        public boolean hasText() {
583            if (state == STATE_RUN_PART) {
584                return parts.get(part).get(reader).hasText();
585            } else {
586                return false;
587            }
588        }
589    
590        public Location getLocation() {
591            return new Location() {
592                public int getCharacterOffset() {
593                    return 0;
594                }
595                public int getColumnNumber() {
596                    return 0;
597                }
598                public int getLineNumber() {
599                    return 0;
600                }
601                public String getPublicId() {
602                    return null;
603                }
604                public String getSystemId() {
605                    return null;
606                }
607            };
608        }
609    
610        public String getVersion() {
611            throw new UnsupportedOperationException("Not implemented");
612        }
613    
614        public boolean isStandalone() {
615            throw new UnsupportedOperationException("Not implemented");
616        }
617    
618        public boolean standaloneSet() {
619            throw new UnsupportedOperationException("Not implemented");
620        }
621    
622        public String getCharacterEncodingScheme() {
623            throw new UnsupportedOperationException("Not implemented");
624        }
625    
626        public String getPITarget() {
627            throw new UnsupportedOperationException("Not implemented");
628        }
629    
630        public String getPIData() {
631            throw new UnsupportedOperationException("Not implemented");
632        }
633        
634        private BindingOperationInfo getOperation(Message message) {
635            BindingOperationInfo operation = message.getExchange().get(
636                    BindingOperationInfo.class);
637            if (operation == null) {
638                throw new Fault(
639                        new Exception("Operation not bound on this message"));
640            }
641            return operation;
642        }
643        
644        private boolean isRequestor(Message message) {
645            return Boolean.TRUE.equals(message.get(Message.REQUESTOR_ROLE));
646        }
647    }