1 /* 2 * Copyright (c) 1997, 2014, 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 26 package com.sun.xml.internal.bind.v2.runtime.unmarshaller; 27 28 import javax.xml.bind.annotation.DomHandler; 29 import javax.xml.transform.Result; 30 import javax.xml.transform.sax.TransformerHandler; 31 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; 32 import org.xml.sax.SAXException; 33 34 /** 35 * Loads a DOM. 36 * 37 * @author Kohsuke Kawaguchi 38 */ 39 public class DomLoader<ResultT extends Result> extends Loader { 40 41 private final DomHandler<?,ResultT> dom; 42 43 /** 44 * Used to capture the state. 45 * 46 * This instance is created for each unmarshalling episode. 47 */ 48 private final class State { 49 50 /** This handler will receive SAX events. */ 51 private TransformerHandler handler = null; 52 53 /** {@link #handler} will produce this result. */ 54 private final ResultT result; 55 56 // nest level of elements. 57 int depth = 1; 58 59 public State( UnmarshallingContext context ) throws SAXException { 60 handler = JAXBContextImpl.createTransformerHandler(context.getJAXBContext().disableSecurityProcessing); 61 result = dom.createUnmarshaller(context); 62 63 handler.setResult(result); 64 65 // emulate the start of documents 66 try { 67 handler.setDocumentLocator(context.getLocator()); 68 handler.startDocument(); 69 declarePrefixes( context, context.getAllDeclaredPrefixes() ); 70 } catch( SAXException e ) { 71 context.handleError(e); 72 throw e; 73 } 74 } 75 76 public Object getElement() { 77 return dom.getElement(result); 78 } 79 80 private void declarePrefixes( UnmarshallingContext context, String[] prefixes ) throws SAXException { 81 for( int i=prefixes.length-1; i>=0; i-- ) { 82 String nsUri = context.getNamespaceURI(prefixes[i]); 83 if(nsUri==null) throw new IllegalStateException("prefix \'"+prefixes[i]+"\' isn't bound"); 84 handler.startPrefixMapping(prefixes[i],nsUri ); 85 } 86 } 87 88 private void undeclarePrefixes( String[] prefixes ) throws SAXException { 89 for( int i=prefixes.length-1; i>=0; i-- ) 90 handler.endPrefixMapping( prefixes[i] ); 91 } 92 } 93 94 public DomLoader(DomHandler<?, ResultT> dom) { 95 super(true); 96 this.dom = dom; 97 } 98 99 @Override 100 public void startElement(UnmarshallingContext.State state, TagName ea) throws SAXException { 101 UnmarshallingContext context = state.getContext(); 102 if (state.getTarget() == null) 103 state.setTarget(new State(context)); 104 105 State s = (State) state.getTarget(); 106 try { 107 s.declarePrefixes(context, context.getNewlyDeclaredPrefixes()); 108 s.handler.startElement(ea.uri, ea.local, ea.getQname(), ea.atts); 109 } catch (SAXException e) { 110 context.handleError(e); 111 throw e; 112 } 113 } 114 115 @Override 116 public void childElement(UnmarshallingContext.State state, TagName ea) throws SAXException { 117 state.setLoader(this); 118 State s = (State) state.getPrev().getTarget(); 119 s.depth++; 120 state.setTarget(s); 121 } 122 123 @Override 124 public void text(UnmarshallingContext.State state, CharSequence text) throws SAXException { 125 if(text.length()==0) 126 return; // there's no point in creating an empty Text node in DOM. 127 try { 128 State s = (State) state.getTarget(); 129 s.handler.characters(text.toString().toCharArray(),0,text.length()); 130 } catch( SAXException e ) { 131 state.getContext().handleError(e); 132 throw e; 133 } 134 } 135 136 @Override 137 public void leaveElement(UnmarshallingContext.State state, TagName ea) throws SAXException { 138 State s = (State) state.getTarget(); 139 UnmarshallingContext context = state.getContext(); 140 141 try { 142 s.handler.endElement(ea.uri, ea.local, ea.getQname()); 143 s.undeclarePrefixes(context.getNewlyDeclaredPrefixes()); 144 } catch( SAXException e ) { 145 context.handleError(e); 146 throw e; 147 } 148 149 if((--s.depth)==0) { 150 // emulate the end of the document 151 try { 152 s.undeclarePrefixes(context.getAllDeclaredPrefixes()); 153 s.handler.endDocument(); 154 } catch( SAXException e ) { 155 context.handleError(e); 156 throw e; 157 } 158 159 // we are done 160 state.setTarget(s.getElement()); 161 } 162 } 163 164 }