/* * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.internal.xjc.reader.dtd; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Stack; import javax.xml.namespace.QName; import com.sun.codemodel.internal.JClass; import com.sun.codemodel.internal.JCodeModel; import com.sun.codemodel.internal.JDefinedClass; import com.sun.codemodel.internal.JPackage; import com.sun.tools.internal.xjc.AbortException; import com.sun.tools.internal.xjc.ErrorReceiver; import com.sun.tools.internal.xjc.Options; import com.sun.tools.internal.xjc.model.CAttributePropertyInfo; import com.sun.tools.internal.xjc.model.CBuiltinLeafInfo; import com.sun.tools.internal.xjc.model.CClassInfo; import com.sun.tools.internal.xjc.model.CPropertyInfo; import com.sun.tools.internal.xjc.model.Model; import com.sun.tools.internal.xjc.model.TypeUse; import com.sun.tools.internal.xjc.model.TypeUseFactory; import com.sun.tools.internal.xjc.model.CDefaultValue; import com.sun.tools.internal.xjc.reader.ModelChecker; import com.sun.tools.internal.xjc.reader.Ring; import com.sun.tools.internal.xjc.reader.dtd.bindinfo.BIAttribute; import com.sun.tools.internal.xjc.reader.dtd.bindinfo.BIElement; import com.sun.tools.internal.xjc.reader.dtd.bindinfo.BIInterface; import com.sun.tools.internal.xjc.reader.dtd.bindinfo.BindInfo; import com.sun.tools.internal.xjc.util.CodeModelClassFactory; import com.sun.tools.internal.xjc.util.ErrorReceiverFilter; import com.sun.xml.internal.bind.api.impl.NameConverter; import com.sun.xml.internal.dtdparser.DTDHandlerBase; import com.sun.xml.internal.dtdparser.DTDParser; import com.sun.xml.internal.dtdparser.InputEntity; import com.sun.xml.internal.xsom.XmlString; import com.sun.istack.internal.SAXParseException2; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.LocatorImpl; /** * Parses DTD grammar along with binding information into BGM. * * @author * Kohsuke KAWAGUCHI */ public class TDTDReader extends DTDHandlerBase { /** * Parses DTD grammar and a binding information into BGM. * *
* This method is just a utility method that covers 80% of the use * cases. * * @param bindingInfo * binding information file, if any. Can be null. */ public static Model parse( InputSource dtd, InputSource bindingInfo, ErrorReceiver errorReceiver, Options opts) { try { // set up a ring final Ring old = Ring.begin(); try { ErrorReceiverFilter ef = new ErrorReceiverFilter(errorReceiver); JCodeModel cm = new JCodeModel(); Model model = new Model(opts,cm,NameConverter.standard,opts.classNameAllocator,null); Ring.add(cm); Ring.add(model); Ring.add(ErrorReceiver.class,ef); TDTDReader reader = new TDTDReader( ef, opts, bindingInfo); DTDParser parser = new DTDParser(); parser.setDtdHandler(reader); if( opts.entityResolver!=null ) parser.setEntityResolver(opts.entityResolver); try { parser.parse(dtd); } catch (SAXParseException e) { return null; // this error was already handled by GrammarReaderController } Ring.get(ModelChecker.class).check(); if(ef.hadError()) return null; else return model; } finally { Ring.end(old); } } catch (IOException e) { errorReceiver.error(new SAXParseException2(e.getMessage(),null,e)); return null; } catch (SAXException e) { errorReceiver.error(new SAXParseException2(e.getMessage(),null,e)); return null; } catch (AbortException e) { // parsing was aborted but the error was already reported return null; } } protected TDTDReader(ErrorReceiver errorReceiver, Options opts, InputSource _bindInfo) throws AbortException { this.entityResolver = opts.entityResolver; this.errorReceiver = new ErrorReceiverFilter(errorReceiver); bindInfo = new BindInfo(model,_bindInfo, this.errorReceiver); classFactory = new CodeModelClassFactory(errorReceiver); } private final EntityResolver entityResolver; /** * binding information. * *
* This is always non-null even if no binding information was specified.
* (In that case, a dummy object will be provided.)
*/
final BindInfo bindInfo;
final Model model = Ring.get(Model.class);
private final CodeModelClassFactory classFactory;
private final ErrorReceiverFilter errorReceiver;
/**
* Element name to its content model definition.
*/
private final Map
* Also checks that the binding file does not contain
* declarations for non-existent elements.
*/
private void processConstructorDeclarations() {
for( BIElement decl: bindInfo.elements() ) {
Element e = elements.get(decl.name());
if(e==null) {
error(decl.getSourceLocation(),
Messages.ERR_BINDINFO_NON_EXISTENT_ELEMENT_DECLARATION,decl.name());
continue; // continue to process next declaration
}
if(!decl.isClass())
// only element-class declaration has constructor definitions
continue;
decl.declareConstructors(e.getClassInfo());
}
}
public void attributeDecl(String elementName, String attributeName, String attributeType, String[] enumeration, short attributeUse, String defaultValue) throws SAXException {
getOrCreateElement(elementName).attributes.add(
createAttribute(elementName, attributeName, attributeType, enumeration, attributeUse, defaultValue)
);
}
protected CPropertyInfo createAttribute(
String elementName, String attributeName, String attributeType,
String[] enums, short attributeUse, String defaultValue )
throws SAXException {
boolean required = attributeUse==USE_REQUIRED;
// get the attribute-property declaration
BIElement edecl = bindInfo.element(elementName);
BIAttribute decl=null;
if(edecl!=null) decl=edecl.attribute(attributeName);
String propName;
if(decl==null) propName = model.getNameConverter().toPropertyName(attributeName);
else propName = decl.getPropertyName();
QName qname = new QName("",attributeName);
// if no declaration is specified, just wrap it by
// a FieldItem and let the normalizer handle its content.
TypeUse use;
if(decl!=null && decl.getConversion()!=null)
use = decl.getConversion().getTransducer();
else
use = builtinConversions.get(attributeType);
CPropertyInfo r = new CAttributePropertyInfo(
propName, null,null/*TODO*/, copyLocator(), qname, use, null, required );
if(defaultValue!=null)
r.defaultValue = CDefaultValue.create( use, new XmlString(defaultValue) );
return r;
}
Element getOrCreateElement( String elementName ) {
Element r = elements.get(elementName);
if(r==null) {
r = new Element(this,elementName);
elements.put(elementName,r);
}
return r;
}
public void startContentModel(String elementName, short contentModelType) throws SAXException {
assert modelGroups.isEmpty();
modelGroups.push(new ModelGroup());
}
public void endContentModel(String elementName, short contentModelType) throws SAXException {
assert modelGroups.size()==1;
Term term = modelGroups.pop().wrapUp();
Element e = getOrCreateElement(elementName);
e.define( contentModelType, term, copyLocator() );
}
private final Stack
* Use {@link #copyLocator()} to get a immutable clone.
*/
private Locator locator;
public void setDocumentLocator(Locator loc) {
this.locator = loc;
}
/**
* Creates a snapshot of the current {@link #locator} values.
*/
private Locator copyLocator(){
return new LocatorImpl(locator);
}
//
//
// builtin datatype handling
//
//
/** Transducers for the built-in types. Read-only. */
private static final Map