001 // 002 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v1.0.1-05/30/2003 05:06 AM(java_re)-fcs 003 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 004 // Any modifications to this file will be lost upon recompilation of the source schema. 005 // Generated on: 2004.10.11 at 12:13:34 EDT 006 // 007 008 /* 009 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 010 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 011 */ 012 package astronomy.data.spectra.impl.runtime; 013 014 import javax.xml.bind.ValidationEvent; 015 import javax.xml.bind.helpers.ValidationEventImpl; 016 import javax.xml.bind.helpers.ValidationEventLocatorImpl; 017 018 import org.relaxng.datatype.Datatype; 019 import org.xml.sax.SAXException; 020 import org.xml.sax.helpers.AttributesImpl; 021 022 import com.sun.msv.grammar.IDContextProvider; 023 import com.sun.msv.util.LightStack; 024 import com.sun.msv.util.StartTagInfo; 025 import com.sun.msv.util.StringRef; 026 import com.sun.msv.verifier.Acceptor; 027 import com.sun.xml.bind.JAXBObject; 028 import com.sun.xml.bind.RIElement; 029 import com.sun.xml.bind.marshaller.IdentifiableObject; 030 import com.sun.xml.bind.serializer.AbortSerializationException; 031 import com.sun.xml.bind.validator.Messages; 032 033 /** 034 * XMLSerializer that calls the native interface of MSV and performs validation. 035 * Used in a pair with a ValidationContext. 036 * 037 * @author Kohsuke Kawaguchi 038 */ 039 public class MSVValidator implements XMLSerializer, IDContextProvider 040 { 041 /** Current acceptor in use. */ 042 private Acceptor acceptor; 043 044 /** Context object that coordinates the entire validation effort. */ 045 private final ValidationContext context; 046 047 /** The object which we are validating. */ 048 private final ValidatableObject target; 049 050 /** 051 * Acceptor stack. Whenever an element is found, the current acceptor is 052 * pushed to the stack and new one is created. 053 * 054 * LightStack is a light-weight stack implementation 055 */ 056 private final LightStack stack = new LightStack(); 057 058 public NamespaceContext2 getNamespaceContext() { 059 return context.getNamespaceContext(); 060 } 061 062 /** 063 * To use this class, call the static validate method. 064 */ 065 private MSVValidator( ValidationContext _ctxt, ValidatableObject vo ) { 066 acceptor = vo.createRawValidator().createAcceptor(); 067 context = _ctxt; 068 target = vo; 069 } 070 071 /** 072 * Validates the specified object and reports any error to the context. 073 */ 074 public static void validate( ValidationContext context, ValidatableObject vo ) 075 throws SAXException { 076 try { 077 new MSVValidator(context,vo)._validate(); 078 } catch( RuntimeException e ) { 079 // sometimes when a conversion between Java object and 080 // lexical value fails, it may throw an exception like 081 // NullPointerException or NumberFormatException. 082 // 083 // catch them and report them as an error. 084 context.reportEvent(vo,e); 085 } 086 } 087 088 /** performs the validation to the object specified in the constructor. */ 089 private void _validate() throws SAXException { 090 // validate attributes 091 target.serializeAttributes(this); 092 093 endAttribute(); 094 095 // validate content model 096 target.serializeElementBody(this); 097 writePendingText(); 098 099 if(!acceptor.isAcceptState(null)) { 100 // some elements are missing 101 // report error 102 StringRef ref = new StringRef(); 103 acceptor.isAcceptState(ref); 104 context.reportEvent(target,ref.str); 105 } 106 } 107 108 public void endNamespaceDecls() throws SAXException { 109 context.getNamespaceContext().endNamespaceDecls(); 110 } 111 112 public void endAttributes() throws SAXException { 113 // TODO: supply StartTagInfo by remembering all reported attributes 114 if(!acceptor.onEndAttributes( null, null )) { 115 // some required attributes are missing. 116 // report a validation error 117 // Note that we don't know which property of this object 118 // causes this error. 119 StringRef ref = new StringRef(); 120 StartTagInfo sti = new StartTagInfo( 121 currentElementUri,currentElementLocalName,currentElementLocalName, 122 emptyAttributes,this); 123 acceptor.onEndAttributes( sti, ref ); 124 context.reportEvent(target,ref.str); 125 } 126 } 127 128 /** stores text reported by the text method. */ 129 private StringBuffer buf = new StringBuffer(); 130 131 public final void text( String text ) throws SAXException { 132 if(text==null) { 133 reportMissingObjectError(); 134 return; 135 } 136 137 if(buf.length()!=0) 138 buf.append(' '); 139 buf.append(text); 140 } 141 142 private void reportMissingObjectError() throws SAXException { 143 ValidationEvent ev = new ValidationEventImpl( 144 ValidationEvent.ERROR, 145 Messages.format(Messages.MISSING_OBJECT), 146 new ValidationEventLocatorImpl(target), 147 new NullPointerException() ); 148 149 reportError(ev); 150 } 151 152 153 // used to keep attribute names until the endAttribute method is called. 154 private String attNamespaceUri; 155 private String attLocalName; 156 157 public void startAttribute( String uri, String local ) { 158 // we will do the processing at the end element 159 this.attNamespaceUri = uri; 160 this.attLocalName = local; 161 } 162 163 public void endAttribute() throws SAXException { 164 if(!acceptor.onAttribute( attNamespaceUri, attLocalName, 165 attLocalName /* we don't have QName, so just use the local name */, 166 buf.toString(), 167 this, null, null )) { 168 169 // either the name was incorrect (which is quite unlikely), 170 // or the value was wrong. 171 // report an error 172 StringRef ref = new StringRef(); 173 acceptor.onAttribute( attNamespaceUri, attLocalName, attLocalName, 174 buf.toString(), this, ref, null ); 175 176 context.reportEvent(target,ref.str); 177 } 178 179 buf = new StringBuffer(); 180 } 181 182 private void writePendingText() throws SAXException { 183 // assert(textBuf!=null); 184 if(!acceptor.onText( buf.toString(), this, null, null )) { 185 // this text is invalid. 186 // report an error 187 StringRef ref = new StringRef(); 188 acceptor.onText( buf.toString(), this, ref, null ); 189 context.reportEvent(target,ref.str); 190 } 191 192 if(buf.length()>1024) 193 buf = new StringBuffer(); 194 else 195 buf.setLength(0); 196 } 197 198 private String currentElementUri; 199 private String currentElementLocalName; 200 201 public void startElement( String uri, String local ) throws SAXException { 202 writePendingText(); 203 204 context.getNamespaceContext().startElement(); 205 206 stack.push(acceptor); 207 208 StartTagInfo sti = new StartTagInfo(uri,local,local,emptyAttributes,this); 209 210 // we pass in an empty attributes, as there is just no way for us to 211 // properly re-construct attributes. Fortunately, I know MSV is not using 212 // attribute values, so this would work, but nevertheless this code is 213 // ugly. This is one of the problems of the "middle" approach. 214 Acceptor child = acceptor.createChildAcceptor( sti, null ); 215 if( child==null ) { 216 // this element is invalid. probably, so this object is invalid 217 // report an error 218 StringRef ref = new StringRef(); 219 child = acceptor.createChildAcceptor( sti, ref ); 220 context.reportEvent(target,ref.str); 221 } 222 223 this.currentElementUri = uri; 224 this.currentElementLocalName = local; 225 226 acceptor = child; 227 } 228 229 public void endElement() throws SAXException { 230 writePendingText(); 231 232 if(!acceptor.isAcceptState(null)) { 233 // some required elements are missing 234 // report error 235 StringRef ref = new StringRef(); 236 acceptor.isAcceptState(ref); 237 context.reportEvent(target,ref.str); 238 } 239 240 // pop the acceptor 241 Acceptor child = acceptor; 242 acceptor = (Acceptor)stack.pop(); 243 if(!acceptor.stepForward( child, null )) { 244 // some required elements are missing. 245 // report an error 246 StringRef ref = new StringRef(); 247 acceptor.stepForward( child, ref ); // force recovery and obtain an error message. 248 249 context.reportEvent(target,ref.str); 250 } 251 252 context.getNamespaceContext().endElement(); 253 } 254 255 256 public void childAsAttributes( JAXBObject o ) throws SAXException { 257 // do nothing 258 259 // either the onMarshallableObjectInElement method 260 // or the onMarshallableObjectInAttributeBody method will be 261 // called for every content tree objects. 262 // 263 // so we don't need to validate an object within this method. 264 } 265 266 public void childAsURIs( JAXBObject o ) throws SAXException { 267 // ditto. 268 } 269 270 271 /** An empty <code>Attributes</code> object. */ 272 private static final AttributesImpl emptyAttributes = new AttributesImpl(); 273 274 /** namespace URI of dummy elements. TODO: allocate one namespace URI for this. */ 275 public static final String DUMMY_ELEMENT_NS = 276 "http://java.sun.com/jaxb/xjc/dummy-elements"; 277 278 public void childAsElementBody( JAXBObject o ) throws SAXException { 279 final ValidatableObject vo = Util.toValidatableObject(o); 280 281 if(vo==null) { 282 reportMissingObjectError(); 283 return; 284 } 285 286 String intfName = vo.getPrimaryInterface().getName(); 287 intfName = intfName.replace('$','.'); 288 289 // if the object implements the RIElement interface, 290 // add a marker attribute to the dummy element. 291 // 292 // For example, if the object is org.acme.impl.FooImpl, 293 // the dummy element will look like 294 // <{DUMMY_ELEMENT_NS}org.acme.Foo 295 // {<URI of this element>}:<local name of this element>="" /> 296 // 297 // This extra attribute is used to validate wildcards. 298 // AttributesImpl atts; 299 // if(o instanceof RIElement) { 300 // RIElement rie = (RIElement)o; 301 // atts = new AttributesImpl(); 302 // atts.addAttribute( 303 // rie.____jaxb_ri____getNamespaceURI(), 304 // rie.____jaxb_ri____getLocalName(), 305 // rie.____jaxb_ri____getLocalName(), // use local name as qname 306 // "CDATA", 307 // ""); // we don't care about the attribute value 308 // } else 309 // atts = emptyAttributes; 310 311 312 // feed a dummy element to the acceptor. 313 StartTagInfo sti = new StartTagInfo( 314 DUMMY_ELEMENT_NS, 315 intfName, 316 intfName/*just pass the local name as QName.*/, 317 emptyAttributes, 318 this ); 319 320 321 Acceptor child = acceptor.createChildAcceptor(sti,null); 322 if(child==null) { 323 // some required elements were missing. report errors 324 StringRef ref = new StringRef(); 325 child = acceptor.createChildAcceptor(sti,ref); 326 context.reportEvent(target,ref.str); 327 } 328 329 if(o instanceof RIElement) { 330 RIElement rie = (RIElement)o; 331 if(!child.onAttribute( 332 rie.____jaxb_ri____getNamespaceURI(), 333 rie.____jaxb_ri____getLocalName(), 334 rie.____jaxb_ri____getLocalName(), 335 "", 336 null, null, null )) 337 338 // this object is not a valid member of the wildcard 339 context.reportEvent(target, 340 Messages.format( Messages.INCORRECT_CHILD_FOR_WILDCARD, 341 rie.____jaxb_ri____getNamespaceURI(), 342 rie.____jaxb_ri____getLocalName() )); 343 } 344 345 child.onEndAttributes(sti,null); 346 347 348 if(!acceptor.stepForward(child,null)) { 349 // this can't be possible, as the dummy element was 350 // generated by XJC. 351 throw new InternalError(); 352 } 353 354 355 // we need a separate validator instance to validate a child object 356 context.validate(vo); 357 358 } 359 360 public void childAsAttributeBody( JAXBObject o ) throws SAXException { 361 /* 362 Dirty quick hack. When we split a schema into fragments, basically 363 every chlid object needs a place holder in the fragment 364 (so that the parent schema fragment can correctly validate that the 365 child objects are at their supposed places.) 366 367 For example, cconsider the following schema: 368 369 imagine: 370 <class> 371 <attribute> 372 <list> 373 <oneOrMore> 374 <ref name="bar"/> 375 </oneOrMore> 376 </list> 377 </attribute> 378 </class> 379 380 In our algorithm, the corresponding schema fragment will be: 381 382 <class> 383 <attribute> 384 <list> 385 <oneOrMore> 386 <value>\u0000full.class.name.of.BarImpl</value> 387 </oneOrMore> 388 </list> 389 </attribute> 390 </class> 391 392 If we find a child object inside an attribute 393 (that's why we are in this method BTW), 394 we generate a class name (with a special marker \u0000). 395 */ 396 397 final ValidatableObject vo = Util.toValidatableObject(o); 398 399 if(vo==null) { 400 reportMissingObjectError(); 401 return; 402 } 403 404 // put a class name with a special marker \u0000. This char is an invalid 405 // XML char, so sensible datatypes should reject this (although many 406 // datatype implementations will accept it in actuality) 407 text("\u0000"+vo.getPrimaryInterface().getName()); 408 409 // validate a child object 410 context.validate(vo); 411 } 412 413 414 public void reportError( ValidationEvent e ) throws AbortSerializationException { 415 context.reportEvent(target,e); 416 } 417 418 // 419 // 420 // ID/IDREF validation 421 // 422 // 423 public String onID( IdentifiableObject owner, String value ) throws SAXException { 424 return context.onID(target,value); 425 } 426 public String onIDREF( IdentifiableObject value ) throws SAXException { 427 return context.onIDREF(target,value.____jaxb____getId()); 428 } 429 430 // 431 // 432 // ValidationContext implementation. Used by MSV to obtain 433 // contextual information related to validation. 434 // 435 // 436 public String getBaseUri() { return null; } 437 public boolean isUnparsedEntity( String entityName ) { 438 // abandon the validation of ENTITY type. 439 return true; 440 } 441 public boolean isNotation( String notation ) { 442 // abandon the validation of NOTATION type. 443 return true; 444 } 445 public void onID( Datatype dt, String s ) { 446 // ID/IDREF validation will be done by ourselves. 447 // so we will not rely on the validator to perform this check. 448 // because we will use multiple instances of validators, so 449 // they cannot check global consistency. 450 451 // see onID/onIDREF of the ValidationContext. 452 } 453 public String resolveNamespacePrefix( String prefix ) { 454 return context.getNamespaceContext().getNamespaceURI(prefix); 455 } 456 457 }