1 /*
2  * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Distribution License v. 1.0, which is available at
6  * http://www.eclipse.org/org/documents/edl-v10.php.
7  *
8  * SPDX-License-Identifier: BSD-3-Clause
9  */

10
11 package com.sun.xml.bind.v2.runtime.unmarshaller;
12
13 import javax.xml.bind.annotation.DomHandler;
14 import javax.xml.transform.Result;
15 import javax.xml.transform.sax.TransformerHandler;
16 import com.sun.xml.bind.v2.runtime.JAXBContextImpl;
17 import org.xml.sax.SAXException;
18
19 /**
20  * Loads a DOM.
21  *
22  * @author Kohsuke Kawaguchi
23  */

24 public class DomLoader<ResultT extends Result> extends Loader {
25
26     private final DomHandler<?,ResultT> dom;
27
28     /**
29      * Used to capture the state.
30      *
31      * This instance is created for each unmarshalling episode.
32      */

33     private final class State {
34         
35         /** This handler will receive SAX events. */
36         private TransformerHandler handler = null;
37
38         /** {@link #handler} will produce this result. */
39         private final ResultT result;
40
41         // nest level of elements.
42         int depth = 1;
43
44         public State( UnmarshallingContext context ) throws SAXException {
45             handler = JAXBContextImpl.createTransformerHandler(context.getJAXBContext().disableSecurityProcessing);
46             result = dom.createUnmarshaller(context);
47
48             handler.setResult(result);
49
50             // emulate the start of documents
51             try {
52                 handler.setDocumentLocator(context.getLocator());
53                 handler.startDocument();
54                 declarePrefixes( context, context.getAllDeclaredPrefixes() );
55             } catch( SAXException e ) {
56                 context.handleError(e);
57                 throw e;
58             }
59         }
60
61         public Object getElement() {
62             return dom.getElement(result);
63         }
64
65         private void declarePrefixes( UnmarshallingContext context, String[] prefixes ) throws SAXException {
66             forint i=prefixes.length-1; i>=0; i-- ) {
67                 String nsUri = context.getNamespaceURI(prefixes[i]);
68                 if(nsUri==null)     throw new IllegalStateException("prefix \'"+prefixes[i]+"\' isn't bound");
69                 handler.startPrefixMapping(prefixes[i],nsUri );
70             }
71         }
72
73         private void undeclarePrefixes( String[] prefixes ) throws SAXException {
74             forint i=prefixes.length-1; i>=0; i-- )
75                 handler.endPrefixMapping( prefixes[i] );
76         }
77     }
78
79     public DomLoader(DomHandler<?, ResultT> dom) {
80         super(true);
81         this.dom = dom;
82     }
83
84     @Override
85     public void startElement(UnmarshallingContext.State state, TagName ea) throws SAXException {
86         UnmarshallingContext context = state.getContext();
87         if (state.getTarget() == null)
88             state.setTarget(new State(context));
89
90         State s = (State) state.getTarget();
91         try {
92             s.declarePrefixes(context, context.getNewlyDeclaredPrefixes());
93             s.handler.startElement(ea.uri, ea.local, ea.getQname(), ea.atts);
94         } catch (SAXException e) {
95             context.handleError(e);
96             throw e;
97         }
98     }
99
100     @Override
101     public void childElement(UnmarshallingContext.State state, TagName ea) throws SAXException {
102         state.setLoader(this);
103         State s = (State) state.getPrev().getTarget();
104         s.depth++;
105         state.setTarget(s);
106     }
107
108     @Override
109     public void text(UnmarshallingContext.State state, CharSequence text) throws SAXException {
110         if(text.length()==0)
111             return;     // there's no point in creating an empty Text node in DOM. 
112         try {
113             State s = (State) state.getTarget();
114             s.handler.characters(text.toString().toCharArray(),0,text.length());
115         } catch( SAXException e ) {
116             state.getContext().handleError(e);
117             throw e;
118         }
119     }
120
121     @Override
122     public void leaveElement(UnmarshallingContext.State state, TagName ea) throws SAXException {
123         State s = (State) state.getTarget();
124         UnmarshallingContext context = state.getContext();
125
126         try {
127             s.handler.endElement(ea.uri, ea.local, ea.getQname());
128             s.undeclarePrefixes(context.getNewlyDeclaredPrefixes());
129         } catch( SAXException e ) {
130             context.handleError(e);
131             throw e;
132         }
133
134         if((--s.depth)==0) {
135             // emulate the end of the document
136             try {
137                 s.undeclarePrefixes(context.getAllDeclaredPrefixes());
138                 s.handler.endDocument();
139             } catch( SAXException e ) {
140                 context.handleError(e);
141                 throw e;
142             }
143
144             // we are done
145             state.setTarget(s.getElement());
146         }
147     }
148
149 }
150