All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.msv.generator.Generator Maven / Gradle / Ivy

/*
 * Copyright (c) 2001-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.sun.msv.generator;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

import org.relaxng.datatype.Datatype;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

import com.sun.msv.datatype.xsd.NmtokenType;
import com.sun.msv.datatype.xsd.StringType;
import com.sun.msv.datatype.xsd.XSDatatype;
import com.sun.msv.grammar.AttributeExp;
import com.sun.msv.grammar.BinaryExp;
import com.sun.msv.grammar.ChoiceExp;
import com.sun.msv.grammar.ConcurExp;
import com.sun.msv.grammar.DataExp;
import com.sun.msv.grammar.ElementExp;
import com.sun.msv.grammar.Expression;
import com.sun.msv.grammar.ExpressionPool;
import com.sun.msv.grammar.ExpressionVisitorVoid;
import com.sun.msv.grammar.InterleaveExp;
import com.sun.msv.grammar.ListExp;
import com.sun.msv.grammar.MixedExp;
import com.sun.msv.grammar.NameClass;
import com.sun.msv.grammar.OneOrMoreExp;
import com.sun.msv.grammar.OtherExp;
import com.sun.msv.grammar.ReferenceExp;
import com.sun.msv.grammar.SequenceExp;
import com.sun.msv.grammar.ValueExp;
import com.sun.msv.grammar.util.ExpressionPrinter;
import com.sun.msv.util.StringPair;
import com.sun.xml.util.XmlChars;

/**
 * generates an XML DOM instance that conforms to the given schema.
 * 
 * @author Kohsuke KAWAGUCHI
 */
public class Generator implements ExpressionVisitorVoid {
	
	/** generation parameters */
	private final GeneratorOption opts;
	private final ExpressionPool pool;
	private final Document domDoc;
	/** current generated node */
	private Node node;
	
	/** current nest level (depth of elements). */
	private int depth = 0;
	
	/** this flag is set to true once an error is generated. */
	private boolean errorGenerated = false;

	/** returns true if generator should cut back. */
	protected boolean cutBack() { return depth>5; }
	
	/** ID tokens that are used */
	private final Set ids = new HashSet();
	/** Text nodes of IDREFs that should be "patched" by IDs. */
	private final Set idrefs = new HashSet();
	
	/** all ElementExps in the grammar. */
	private final ElementExp[] elementDecls;
	/** all AttributeExps in the grammar. */
	private final AttributeExp[] attributeDecls;
	
	/** generates instance by using default settings. */
	public static void generate( Expression exp, Document emptyDoc ) {
		generate( exp, emptyDoc, new GeneratorOption() );
	}
	
	/** generates instance by custom settings. */
	public static void generate( Expression exp, Document emptyDoc, GeneratorOption opts ) {
		Generator g;
		
		for( int i=0; i<10; i++ ) {
			// make it empty.
			while( emptyDoc.hasChildNodes())
				emptyDoc.removeChild(emptyDoc.getFirstChild());
			
			do {
				while( emptyDoc.getFirstChild()!=null ) // delete any existing children
					emptyDoc.removeChild( emptyDoc.getFirstChild() );
				
				g = new Generator(exp,emptyDoc,opts);
				exp.visit(g);
				// if error ratio is specified and no error is generated, do it again.
			}while( !g.errorGenerated && opts.errorSpecified() );
		
		
			Object[] ids = g.ids.toArray();
			if( ids.length==0 && g.idrefs.size()!=0 )
				continue;	// IDREF is generated but no ID is generated.
							// try again.
		
			// patch IDREF.
			Iterator itr = g.idrefs.iterator();
			while( itr.hasNext() ) {
				Text node = (Text)itr.next();
				node.setData( (String)ids[opts.random.nextInt(ids.length)] );
			}
			return;
		}
		
		throw new Error("no ID");
	}
	
	protected Generator( Expression exp, Document emptyDoc, GeneratorOption opts ) {
		opts.fillInByDefault();
		this.opts = opts;
		this.pool = opts.pool;
		node = domDoc = emptyDoc;
		
		// collect element and attribute decls.
		Set[] s= ElementDeclCollector.collect(exp);
		elementDecls = new ElementExp[s[0].size()];
		s[0].toArray(elementDecls);
		attributeDecls = new AttributeExp[s[1].size()];
		s[1].toArray(attributeDecls);
	}
	
	/** annotate DOM by adding a comment that an error is generated. */
	private void noteError( String error ) {
		errorGenerated = true;
		if( !opts.insertComment )	return;
		
		Node com = domDoc.createComment("  "+error+"  ");
		
		Node n = node;
		if( n.getNodeType()==Node.ATTRIBUTE_NODE ) {
			n = ((Attr)n).getOwnerElement();
			n.insertBefore( com, n.getFirstChild() );
		} else {
			n.appendChild(com);
		}
	}
	
	
	public void onEpsilon() {}
	public void onNullSet() { throw new Error(); }	// assertion failed
	
	public void onSequence( SequenceExp exp ) {
		if(!(exp.exp1 instanceof AttributeExp)
		&& !(exp.exp2 instanceof AttributeExp) ) {
			// sequencing error of attribute is meaningless.
			if( opts.random.nextDouble() < opts.probSeqError ) {
				// generate sequencing error
				noteError("swap sequence to "+
						  ExpressionPrinter.printSmallest(exp.exp2)+","+
						  ExpressionPrinter.printSmallest(exp.exp1) );
				exp.exp2.visit(this);
				exp.exp1.visit(this);
				return;
			}
		}
		
		// generate valid instance.
		exp.exp1.visit(this);
		exp.exp2.visit(this);
	}
	
	public void onInterleave( InterleaveExp ip ) {
		// collect children
		Vector vec = getChildren(ip);
		
		Node old = node;
		// generate XML fragment for each child.
		for( int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy