1/*
2 * Copyright (c) 2005, 2016, 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 */
25package com.sun.xml.internal.stream.events;
26
27import com.sun.org.apache.xerces.internal.impl.PropertyManager;
28import java.util.List;
29import javax.xml.stream.util.XMLEventAllocator;
30import javax.xml.stream.*;
31import javax.xml.stream.events.*;
32import javax.xml.XMLConstants;
33import javax.xml.namespace.QName;
34import com.sun.org.apache.xerces.internal.util.NamespaceContextWrapper;
35import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
36import javax.xml.stream.util.XMLEventConsumer;
37
38/**
39 * Implementation of XMLEvent Allocator.
40 *
41 * @author Neeraj.bajaj@sun.com, k.venugopal@sun.com
42 */
43public class XMLEventAllocatorImpl implements XMLEventAllocator {
44
45    /**
46     * Creates a new instance of XMLEventAllocator
47     */
48    public XMLEventAllocatorImpl() {
49    }
50
51    public XMLEvent allocate(XMLStreamReader xMLStreamReader) throws XMLStreamException {
52        if (xMLStreamReader == null) {
53            throw new XMLStreamException("Reader cannot be null");
54        }
55        //        allocate is not supposed to change the state of the reader so we shouldn't be calling next.
56        //        return getNextEvent(xMLStreamReader);
57        return getXMLEvent(xMLStreamReader);
58    }
59
60    public void allocate(XMLStreamReader xMLStreamReader, XMLEventConsumer xMLEventConsumer)
61            throws XMLStreamException {
62        XMLEvent currentEvent = getXMLEvent(xMLStreamReader);
63        if (currentEvent != null) {
64            xMLEventConsumer.add(currentEvent);
65        }
66
67        return;
68    }
69
70    public javax.xml.stream.util.XMLEventAllocator newInstance() {
71        return new XMLEventAllocatorImpl();
72    }
73
74    //REVISIT: shouldn't we be using XMLEventFactory to create events.
75    XMLEvent getXMLEvent(XMLStreamReader streamReader) {
76        XMLEvent event = null;
77        //returns the current event
78        int eventType = streamReader.getEventType();
79        switch (eventType) {
80
81            case XMLEvent.START_ELEMENT: {
82                StartElementEvent startElementEvent = new StartElementEvent(getQName(streamReader));
83                fillAttributes(startElementEvent, streamReader);
84                //we might have different XMLStreamReader so check every time for
85                //the namespace aware property. we should be setting namespace
86                //related values only when isNamespaceAware is 'true'
87                if (((Boolean) streamReader.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE))) {
88                    fillNamespaceAttributes(startElementEvent, streamReader);
89                    setNamespaceContext(startElementEvent, streamReader);
90                }
91
92                startElementEvent.setLocation(streamReader.getLocation());
93                event = startElementEvent;
94                break;
95            }
96            case XMLEvent.END_ELEMENT: {
97                EndElementEvent endElementEvent = new EndElementEvent(getQName(streamReader));
98                endElementEvent.setLocation(streamReader.getLocation());
99
100                if (((Boolean) streamReader.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE))) {
101                    fillNamespaceAttributes(endElementEvent, streamReader);
102                }
103                event = endElementEvent;
104                break;
105            }
106            case XMLEvent.PROCESSING_INSTRUCTION: {
107                ProcessingInstructionEvent piEvent = new ProcessingInstructionEvent(
108                        streamReader.getPITarget(), streamReader.getPIData());
109                piEvent.setLocation(streamReader.getLocation());
110                event = piEvent;
111                break;
112            }
113            case XMLEvent.CHARACTERS: {
114                CharacterEvent cDataEvent = new CharacterEvent(streamReader.getText());
115                cDataEvent.setLocation(streamReader.getLocation());
116                event = cDataEvent;
117                break;
118            }
119            case XMLEvent.COMMENT: {
120                CommentEvent commentEvent = new CommentEvent(streamReader.getText());
121                commentEvent.setLocation(streamReader.getLocation());
122                event = commentEvent;
123                break;
124            }
125            case XMLEvent.START_DOCUMENT: {
126                StartDocumentEvent sdEvent = new StartDocumentEvent();
127                sdEvent.setVersion(streamReader.getVersion());
128                sdEvent.setEncoding(streamReader.getEncoding());
129                if (streamReader.getCharacterEncodingScheme() != null) {
130                    sdEvent.setDeclaredEncoding(true);
131                } else {
132                    sdEvent.setDeclaredEncoding(false);
133                }
134                sdEvent.setStandalone(streamReader.isStandalone());
135                sdEvent.setLocation(streamReader.getLocation());
136                event = sdEvent;
137                break;
138            }
139            case XMLEvent.END_DOCUMENT: {
140                EndDocumentEvent endDocumentEvent = new EndDocumentEvent();
141                endDocumentEvent.setLocation(streamReader.getLocation());
142                event = endDocumentEvent;
143                break;
144            }
145            case XMLEvent.ENTITY_REFERENCE: {
146                EntityReferenceEvent entityEvent = new EntityReferenceEvent(streamReader.getLocalName(),
147                        new EntityDeclarationImpl(streamReader.getLocalName(), streamReader.getText()));
148                entityEvent.setLocation(streamReader.getLocation());
149                event = entityEvent;
150                break;
151
152            }
153            case XMLEvent.ATTRIBUTE: {
154                event = null;
155                break;
156            }
157            case XMLEvent.DTD: {
158                DTDEvent dtdEvent = new DTDEvent(streamReader.getText());
159                dtdEvent.setLocation(streamReader.getLocation());
160                @SuppressWarnings("unchecked")
161                List<EntityDeclaration> entities = (List<EntityDeclaration>)
162                        streamReader.getProperty(PropertyManager.STAX_ENTITIES);
163                if (entities != null && entities.size() != 0) {
164                    dtdEvent.setEntities(entities);
165                }
166                @SuppressWarnings("unchecked")
167                List<NotationDeclaration> notations = (List<NotationDeclaration>)
168                        streamReader.getProperty(PropertyManager.STAX_NOTATIONS);
169                if (notations != null && !notations.isEmpty()) {
170                    dtdEvent.setNotations(notations);
171                }
172                event = dtdEvent;
173                break;
174            }
175            case XMLEvent.CDATA: {
176                CharacterEvent cDataEvent = new CharacterEvent(streamReader.getText(), true);
177                cDataEvent.setLocation(streamReader.getLocation());
178                event = cDataEvent;
179                break;
180            }
181            case XMLEvent.SPACE: {
182                CharacterEvent spaceEvent = new CharacterEvent(streamReader.getText(), false, true);
183                spaceEvent.setLocation(streamReader.getLocation());
184                event = spaceEvent;
185                break;
186            }
187        }
188        return event;
189    }
190
191    //this function is not used..
192    protected XMLEvent getNextEvent(XMLStreamReader streamReader) throws XMLStreamException {
193        //advance the reader to next event.
194        streamReader.next();
195        return getXMLEvent(streamReader);
196    }
197
198    protected void fillAttributes(StartElementEvent event, XMLStreamReader xmlr) {
199
200        int len = xmlr.getAttributeCount();
201        QName qname = null;
202        AttributeImpl attr = null;
203        NamespaceImpl nattr = null;
204        for (int i = 0; i < len; i++) {
205            qname = xmlr.getAttributeName(i);
206            //this method doesn't include namespace declarations
207            //so we can be sure that there wont be any namespace declaration as part of this function call
208            //we can avoid this check - nb.
209            /**
210             * prefix = qname.getPrefix(); localpart = qname.getLocalPart(); if
211             * (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE) ) { attr = new
212             * NamespaceImpl(localpart,xmlr.getAttributeValue(i)); }else if
213             * (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)){ attr = new
214             * NamespaceImpl(xmlr.getAttributeValue(i)); }else{ attr = new
215             * AttributeImpl(); attr.setName(qname); }
216             *
217             */
218            attr = new AttributeImpl();
219            attr.setName(qname);
220            attr.setAttributeType(xmlr.getAttributeType(i));
221            attr.setSpecified(xmlr.isAttributeSpecified(i));
222            attr.setValue(xmlr.getAttributeValue(i));
223            event.addAttribute(attr);
224        }
225    }
226
227    protected void fillNamespaceAttributes(StartElementEvent event, XMLStreamReader xmlr) {
228        int count = xmlr.getNamespaceCount();
229        String uri = null;
230        String prefix = null;
231        NamespaceImpl attr = null;
232        for (int i = 0; i < count; i++) {
233            uri = xmlr.getNamespaceURI(i);
234            prefix = xmlr.getNamespacePrefix(i);
235            if (prefix == null) {
236                prefix = XMLConstants.DEFAULT_NS_PREFIX;
237            }
238            attr = new NamespaceImpl(prefix, uri);
239            event.addNamespaceAttribute(attr);
240        }
241    }
242
243    protected void fillNamespaceAttributes(EndElementEvent event, XMLStreamReader xmlr) {
244        int count = xmlr.getNamespaceCount();
245        String uri = null;
246        String prefix = null;
247        NamespaceImpl attr = null;
248        for (int i = 0; i < count; i++) {
249            uri = xmlr.getNamespaceURI(i);
250            prefix = xmlr.getNamespacePrefix(i);
251            if (prefix == null) {
252                prefix = XMLConstants.DEFAULT_NS_PREFIX;
253            }
254            attr = new NamespaceImpl(prefix, uri);
255            event.addNamespace(attr);
256        }
257    }
258
259    //Revisit : Creating a new Namespacecontext for now.
260    //see if we can do better job.
261    private void setNamespaceContext(StartElementEvent event, XMLStreamReader xmlr) {
262        NamespaceContextWrapper contextWrapper = (NamespaceContextWrapper) xmlr.getNamespaceContext();
263        NamespaceSupport ns = new NamespaceSupport(contextWrapper.getNamespaceContext());
264        event.setNamespaceContext(new NamespaceContextWrapper(ns));
265    }
266
267    private QName getQName(XMLStreamReader xmlr) {
268        return new QName(xmlr.getNamespaceURI(), xmlr.getLocalName(),
269                xmlr.getPrefix());
270    }
271}
272