1/*
2 * Copyright (c) 1997, 2015, 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
26package com.sun.xml.internal.ws.util.xml;
27
28import java.io.IOException;
29
30import javax.xml.bind.attachment.AttachmentMarshaller;
31import javax.xml.stream.XMLStreamConstants;
32import javax.xml.stream.XMLStreamException;
33import javax.xml.stream.XMLStreamReader;
34import javax.xml.stream.XMLStreamWriter;
35import javax.xml.XMLConstants;
36
37import com.sun.xml.internal.ws.streaming.MtomStreamWriter;
38import com.sun.xml.internal.org.jvnet.staxex.Base64Data;
39import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx;
40import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx;
41
42/**
43 * Reads a sub-tree from {@link XMLStreamReader} and writes to {@link XMLStreamWriter}
44 * as-is.
45 *
46 * <p>
47 * This class can be sub-classed to implement a simple transformation logic.
48 *
49 * @author Kohsuke Kawaguchi
50 * @author Ryan Shoemaker
51 *
52 * @deprecated use com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter
53 */
54public class XMLStreamReaderToXMLStreamWriter {
55
56    private static final int BUF_SIZE = 4096;
57
58    protected XMLStreamReader in;
59    protected XMLStreamWriter out;
60
61    private char[] buf;
62
63    boolean optimizeBase64Data = false;
64
65    AttachmentMarshaller mtomAttachmentMarshaller;
66
67    /**
68     * Reads one subtree and writes it out.
69     *
70     * <p>
71     * The {@link XMLStreamWriter} never receives a start/end document event.
72     * Those need to be written separately by the caller.
73     */
74    public void bridge(XMLStreamReader in, XMLStreamWriter out) throws XMLStreamException {
75        assert in!=null && out!=null;
76        this.in = in;
77        this.out = out;
78
79        optimizeBase64Data = (in instanceof XMLStreamReaderEx);
80
81        if (out instanceof XMLStreamWriterEx && out instanceof MtomStreamWriter) {
82            mtomAttachmentMarshaller = ((MtomStreamWriter) out).getAttachmentMarshaller();
83        }
84        // remembers the nest level of elements to know when we are done.
85        int depth=0;
86
87        buf = new char[BUF_SIZE];
88
89        // if the parser is at the start tag, proceed to the first element
90        int event = in.getEventType();
91        if(event == XMLStreamConstants.START_DOCUMENT) {
92            // nextTag doesn't correctly handle DTDs
93            while( !in.isStartElement() ) {
94                event = in.next();
95                if (event == XMLStreamConstants.COMMENT)
96                    handleComment();
97            }
98        }
99
100
101        if( event!=XMLStreamConstants.START_ELEMENT)
102            throw new IllegalStateException("The current event is not START_ELEMENT\n but " + event);
103
104        do {
105            // These are all of the events listed in the javadoc for
106            // XMLEvent.
107            // The spec only really describes 11 of them.
108            switch (event) {
109                case XMLStreamConstants.START_ELEMENT :
110                    depth++;
111                    handleStartElement();
112                    break;
113                case XMLStreamConstants.END_ELEMENT :
114                    handleEndElement();
115                    depth--;
116                    if(depth==0)
117                        return;
118                    break;
119                case XMLStreamConstants.CHARACTERS :
120                    handleCharacters();
121                    break;
122                case XMLStreamConstants.ENTITY_REFERENCE :
123                    handleEntityReference();
124                    break;
125                case XMLStreamConstants.PROCESSING_INSTRUCTION :
126                    handlePI();
127                    break;
128                case XMLStreamConstants.COMMENT :
129                    handleComment();
130                    break;
131                case XMLStreamConstants.DTD :
132                    handleDTD();
133                    break;
134                case XMLStreamConstants.CDATA :
135                    handleCDATA();
136                    break;
137                case XMLStreamConstants.SPACE :
138                    handleSpace();
139                    break;
140                case XMLStreamConstants.END_DOCUMENT:
141                    throw new XMLStreamException("Malformed XML at depth="+depth+", Reached EOF. Event="+event);
142                default :
143                    throw new XMLStreamException("Cannot process event: " + event);
144            }
145
146            event=in.next();
147        } while (depth!=0);
148    }
149
150    protected void handlePI() throws XMLStreamException {
151        out.writeProcessingInstruction(
152            in.getPITarget(),
153            in.getPIData());
154    }
155
156
157    protected void handleCharacters() throws XMLStreamException {
158
159        CharSequence c = null;
160
161        if (optimizeBase64Data) {
162            c = ((XMLStreamReaderEx)in).getPCDATA();
163        }
164
165        if ((c != null) && (c instanceof Base64Data)) {
166            if (mtomAttachmentMarshaller != null) {
167                Base64Data b64d = (Base64Data) c;
168                ((XMLStreamWriterEx)out).writeBinary(b64d.getDataHandler());
169            } else {
170                try {
171                    ((Base64Data)c).writeTo(out);
172                } catch (IOException e) {
173                    throw new XMLStreamException(e);
174                }
175            }
176        } else {
177            for (int start=0,read=buf.length; read == buf.length; start+=buf.length) {
178                read = in.getTextCharacters(start, buf, 0, buf.length);
179                out.writeCharacters(buf, 0, read);
180            }
181        }
182    }
183
184    protected void handleEndElement() throws XMLStreamException {
185        out.writeEndElement();
186    }
187
188    protected void handleStartElement() throws XMLStreamException {
189        String nsUri = in.getNamespaceURI();
190        out.writeStartElement(
191            fixNull(in.getPrefix()),
192            in.getLocalName(),
193            fixNull(nsUri)
194        );
195
196        // start namespace bindings
197        int nsCount = in.getNamespaceCount();
198        for (int i = 0; i < nsCount; i++) {
199            out.writeNamespace(
200                in.getNamespacePrefix(i),
201                fixNull(in.getNamespaceURI(i)));    // zephyr doesn't like null, I don't know what is correct, so just fix null to "" for now
202        }
203
204        // write attributes
205        int attCount = in.getAttributeCount();
206        for (int i = 0; i < attCount; i++) {
207            handleAttribute(i);
208        }
209    }
210
211    /**
212     * Writes out the {@code i}-th attribute of the current element.
213     *
214     * <p>
215     * Used from {@link #handleStartElement()}.
216     */
217    protected void handleAttribute(int i) throws XMLStreamException {
218        String nsUri = in.getAttributeNamespace(i);
219        String prefix = in.getAttributePrefix(i);
220         if (fixNull(nsUri).equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
221             //Its a namespace decl, ignore as it is already written.
222             return;
223         }
224
225        if(nsUri==null || prefix == null || prefix.equals("")) {
226            out.writeAttribute(
227                in.getAttributeLocalName(i),
228                in.getAttributeValue(i)
229            );
230        } else {
231            out.writeAttribute(
232                prefix,
233                nsUri,
234                in.getAttributeLocalName(i),
235                in.getAttributeValue(i)
236            );
237        }
238    }
239
240    protected void handleDTD() throws XMLStreamException {
241        out.writeDTD(in.getText());
242    }
243
244    protected void handleComment() throws XMLStreamException {
245        out.writeComment(in.getText());
246    }
247
248    protected void handleEntityReference() throws XMLStreamException {
249        out.writeEntityRef(in.getText());
250    }
251
252    protected void handleSpace() throws XMLStreamException {
253        handleCharacters();
254    }
255
256    protected void handleCDATA() throws XMLStreamException {
257        out.writeCData(in.getText());
258    }
259
260    private static String fixNull(String s) {
261        if(s==null)     return "";
262        else            return s;
263    }
264}
265