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