1 /* 2 * Copyright (c) 1997, 2011, 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.tools.internal.xjc.reader.dtd.bindinfo; 27 28 import java.io.IOException; 29 import java.util.Collection; 30 import java.util.HashMap; 31 import java.util.Map; 32 33 import javax.xml.parsers.ParserConfigurationException; 34 import javax.xml.parsers.SAXParserFactory; 35 import javax.xml.validation.ValidatorHandler; 36 37 import com.sun.codemodel.internal.ClassType; 38 import com.sun.codemodel.internal.JClass; 39 import com.sun.codemodel.internal.JClassAlreadyExistsException; 40 import com.sun.codemodel.internal.JCodeModel; 41 import com.sun.codemodel.internal.JDefinedClass; 42 import com.sun.codemodel.internal.JPackage; 43 import com.sun.istack.internal.SAXParseException2; 44 import com.sun.tools.internal.xjc.AbortException; 45 import com.sun.tools.internal.xjc.ErrorReceiver; 46 import com.sun.tools.internal.xjc.SchemaCache; 47 import com.sun.tools.internal.xjc.model.CCustomizations; 48 import com.sun.tools.internal.xjc.model.CPluginCustomization; 49 import com.sun.tools.internal.xjc.model.Model; 50 import com.sun.tools.internal.xjc.reader.Const; 51 import com.sun.tools.internal.xjc.util.CodeModelClassFactory; 52 import com.sun.tools.internal.xjc.util.ErrorReceiverFilter; 53 import com.sun.tools.internal.xjc.util.ForkContentHandler; 54 55 import org.w3c.dom.Document; 56 import org.w3c.dom.Element; 57 import org.xml.sax.InputSource; 58 import org.xml.sax.SAXException; 59 import org.xml.sax.XMLReader; 60 61 /** 62 * Root of the binding information. 63 */ 64 public class BindInfo 65 { 66 /** Controller object that can be used to report errors. */ 67 protected final ErrorReceiver errorReceiver; 68 69 /*package*/ final Model model; 70 71 /** 72 * The -p option that should control the default Java package that 73 * will contain the generated code. Null if unspecified. This takes 74 * precedence over the value specified in the binding file. 75 */ 76 private final String defaultPackage; 77 78 public BindInfo(Model model, InputSource source, ErrorReceiver _errorReceiver) throws AbortException { 79 this( model, parse(model,source,_errorReceiver), _errorReceiver); 80 } 81 82 public BindInfo(Model model, Document _dom, ErrorReceiver _errorReceiver) { 83 this.model = model; 84 this.dom = _dom.getDocumentElement(); 85 this.codeModel = model.codeModel; 86 this.errorReceiver = _errorReceiver; 87 this.classFactory = new CodeModelClassFactory(_errorReceiver); 88 // TODO: decide name converter from the binding file 89 90 this.defaultPackage = model.options.defaultPackage; 91 92 // copy global customizations to the model 93 model.getCustomizations().addAll(getGlobalCustomizations()); 94 95 // process element declarations 96 for( Element ele : DOMUtil.getChildElements(dom,"element")) { 97 BIElement e = new BIElement(this,ele); 98 elements.put(e.name(),e); 99 } 100 101 // add built-in conversions 102 BIUserConversion.addBuiltinConversions(this,conversions); 103 104 // process conversion declarations 105 for( Element cnv : DOMUtil.getChildElements(dom,"conversion")) { 106 BIConversion c = new BIUserConversion(this,cnv); 107 conversions.put(c.name(),c); 108 } 109 for( Element en : DOMUtil.getChildElements(dom,"enumeration")) { 110 BIConversion c = BIEnumeration.create( en, this ); 111 conversions.put(c.name(),c); 112 } 113 // TODO: check the uniquness of conversion name 114 115 116 // process interface definitions 117 for( Element itf : DOMUtil.getChildElements(dom,"interface")) { 118 BIInterface c = new BIInterface(itf); 119 interfaces.put(c.name(),c); 120 } 121 } 122 123 124 /** CodeModel object that is used by this binding file. */ 125 final JCodeModel codeModel; 126 127 /** Wrap the codeModel object and automate error reporting. */ 128 final CodeModelClassFactory classFactory; 129 130 /** DOM tree that represents binding info. */ 131 private final Element dom; 132 133 /** Conversion declarations. */ 134 private final Map<String,BIConversion> conversions = new HashMap<String,BIConversion>(); 135 136 /** Element declarations keyed by names. */ 137 private final Map<String,BIElement> elements = new HashMap<String,BIElement>(); 138 139 /** interface declarations keyed by names. */ 140 private final Map<String,BIInterface> interfaces = new HashMap<String,BIInterface>(); 141 142 143 /** XJC extension namespace. */ 144 private static final String XJC_NS = Const.XJC_EXTENSION_URI; 145 146 // 147 // 148 // Exposed public methods 149 // 150 // 151 /** Gets the serialVersionUID if it's turned on. */ 152 public Long getSerialVersionUID() { 153 Element serial = DOMUtil.getElement(dom,XJC_NS,"serializable"); 154 if(serial==null) return null; 155 156 String v = DOMUtil.getAttribute(serial,"uid"); 157 if(v==null) v="1"; 158 return new Long(v); 159 } 160 161 /** Gets the xjc:superClass customization if it's turned on. */ 162 public JClass getSuperClass() { 163 Element sc = DOMUtil.getElement(dom,XJC_NS,"superClass"); 164 if (sc == null) return null; 165 166 JDefinedClass c; 167 168 try { 169 String v = DOMUtil.getAttribute(sc,"name"); 170 if(v==null) return null; 171 c = codeModel._class(v); 172 c.hide(); 173 } catch (JClassAlreadyExistsException e) { 174 c = e.getExistingClass(); 175 } 176 177 return c; 178 } 179 180 /** Gets the xjc:superInterface customization if it's turned on. */ 181 public JClass getSuperInterface() { 182 Element sc = DOMUtil.getElement(dom,XJC_NS,"superInterface"); 183 if (sc == null) return null; 184 185 String name = DOMUtil.getAttribute(sc,"name"); 186 if (name == null) return null; 187 188 JDefinedClass c; 189 190 try { 191 c = codeModel._class(name, ClassType.INTERFACE); 192 c.hide(); 193 } catch (JClassAlreadyExistsException e) { 194 c = e.getExistingClass(); 195 } 196 197 return c; 198 } 199 200 /** 201 * Gets the specified package name (options/@package). 202 */ 203 public JPackage getTargetPackage() { 204 if(model.options.defaultPackage!=null) 205 // "-p" takes precedence over everything else 206 return codeModel._package(model.options.defaultPackage); 207 208 String p; 209 if( defaultPackage!=null ) 210 p = defaultPackage; 211 else 212 p = getOption("package", ""); 213 return codeModel._package(p); 214 } 215 216 /** 217 * Gets the conversion declaration from the binding info. 218 * 219 * @return 220 * A non-null valid BIConversion object. 221 */ 222 public BIConversion conversion(String name) { 223 BIConversion r = conversions.get(name); 224 if (r == null) 225 throw new AssertionError("undefined conversion name: this should be checked by the validator before we read it"); 226 return r; 227 } 228 229 /** 230 * Gets the element declaration from the binding info. 231 * 232 * @return 233 * If there is no declaration with a given name, 234 * this method returns null. 235 */ 236 public BIElement element( String name ) { 237 return elements.get(name); 238 } 239 /** Iterates all {@link BIElement}s in a read-only set. */ 240 public Collection<BIElement> elements() { 241 return elements.values(); 242 } 243 244 /** Returns all {@link BIInterface}s in a read-only set. */ 245 public Collection<BIInterface> interfaces() { 246 return interfaces.values(); 247 } 248 249 /** 250 * Gets the list of top-level {@link CPluginCustomization}s. 251 */ 252 private CCustomizations getGlobalCustomizations() { 253 CCustomizations r=null; 254 for( Element e : DOMUtil.getChildElements(dom) ) { 255 if(!model.options.pluginURIs.contains(e.getNamespaceURI())) 256 continue; // this isn't a plugin customization 257 if(r==null) 258 r = new CCustomizations(); 259 r.add(new CPluginCustomization(e, DOMLocator.getLocationInfo(e))); 260 } 261 262 if(r==null) r = CCustomizations.EMPTY; 263 return new CCustomizations(r); 264 } 265 266 267 268 269 // 270 // 271 // Internal utility methods 272 // 273 // 274 275 276 /** Gets the value from the option element. */ 277 private String getOption(String attName, String defaultValue) { 278 Element opt = DOMUtil.getElement(dom,"options"); 279 if (opt != null) { 280 String s = DOMUtil.getAttribute(opt,attName); 281 if (s != null) 282 return s; 283 } 284 return defaultValue; 285 } 286 287 /** 288 * Lazily parsed schema for the binding file. 289 */ 290 private static SchemaCache bindingFileSchema = new SchemaCache(BindInfo.class.getResource("bindingfile.xsd")); 291 292 /** 293 * Parses an InputSource into dom4j Document. 294 * Returns null in case of an exception. 295 */ 296 private static Document parse( Model model, InputSource is, ErrorReceiver receiver ) throws AbortException { 297 try { 298 ValidatorHandler validator = bindingFileSchema.newValidator(); 299 300 // set up the pipe line as : 301 // /-> extensionChecker -> validator 302 // parser-> -< 303 // \-> DOM builder 304 SAXParserFactory pf = SAXParserFactory.newInstance(); 305 pf.setNamespaceAware(true); 306 DOMBuilder builder = new DOMBuilder(); 307 308 ErrorReceiverFilter controller = new ErrorReceiverFilter(receiver); 309 validator.setErrorHandler(controller); 310 XMLReader reader = pf.newSAXParser().getXMLReader(); 311 reader.setErrorHandler(controller); 312 313 DTDExtensionBindingChecker checker = new DTDExtensionBindingChecker("", model.options, controller); 314 checker.setContentHandler(validator); 315 316 reader.setContentHandler(new ForkContentHandler(checker,builder)); 317 318 reader.parse(is); 319 320 if(controller.hadError()) throw new AbortException(); 321 return (Document)builder.getDOM(); 322 } catch( IOException e ) { 323 receiver.error( new SAXParseException2(e.getMessage(),null,e) ); 324 } catch( SAXException e ) { 325 receiver.error( new SAXParseException2(e.getMessage(),null,e) ); 326 } catch( ParserConfigurationException e ) { 327 receiver.error( new SAXParseException2(e.getMessage(),null,e) ); 328 } 329 330 throw new AbortException(); 331 } 332 }