/*
* soapUI, copyright (C) 2004-2011 eviware.com
*
* soapUI is free software; you can redistribute it and/or modify it under the
* terms of version 2.1 of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* soapUI 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 Lesser General Public License for more details at gnu.org.
*/
package com.eviware.soapui.impl.wadl.inference.schema;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import com.eviware.soapui.impl.wadl.inference.ConflictHandler;
import com.eviware.soapui.impl.wadl.inference.ConflictHandler.Event;
import com.eviware.soapui.impl.wadl.inference.schema.types.ComplexType;
import com.eviware.soapui.impl.wadl.inference.schema.types.EmptyType;
import com.eviware.soapui.inferredSchema.ComplexTypeConfig;
import com.eviware.soapui.inferredSchema.MapEntryConfig;
import com.eviware.soapui.inferredSchema.ParticleConfig;
import com.eviware.soapui.inferredSchema.SchemaConfig;
import com.eviware.soapui.support.StringUtils;
/**
* Represents an inferred schema for a single namespace.
*
* @author Dain Nilsson
*/
public class Schema
{
private SchemaSystem schemaSystem;
private String namespace;
private Map<String, String> prefixes;
private Map<String, ComplexType> types;
private List<Particle> particles;
private EmptyType empty = new EmptyType( this );
/**
* Constructs a blank new Schema for the given namespace in the given
* SchemaSystem.
*
* @param namespace
* The namespace for the new schema.
* @param schemaSystem
* The SchemaSystem in which to place the newly created Schema.
*/
public Schema( String namespace, SchemaSystem schemaSystem )
{
this.schemaSystem = schemaSystem;
this.namespace = namespace;
prefixes = new HashMap<String, String>();
particles = new ArrayList<Particle>();
types = new HashMap<String, ComplexType>();
putPrefixForNamespace( "xs", Settings.xsdns );
}
/**
* Constructs a Schema object using previously saved data.
*
* @param xml
* The XmlObject to which data has previously been saved.
* @param schemaSystem
* The SchemaSystem in which to place the newly created Schema.
*/
public Schema( SchemaConfig xml, SchemaSystem schemaSystem )
{
this.schemaSystem = schemaSystem;
namespace = xml.getNamespace();
prefixes = new HashMap<String, String>();
particles = new ArrayList<Particle>();
types = new HashMap<String, ComplexType>();
for( MapEntryConfig entry : xml.getPrefixList() )
prefixes.put( entry.getKey(), entry.getValue() );
for( ParticleConfig item : xml.getParticleList() )
{
particles.add( Particle.Factory.parse( item, this ) );
}
for( ComplexTypeConfig item : xml.getComplexTypeList() )
{
types.put( item.getName(), new ComplexType( item, this ) );
}
}
/**
* Save the Schema to an XmlObject.
*
* @param xml
* A blank XmlObject to save to.
*/
public void save( SchemaConfig xml )
{
xml.setNamespace( namespace );
for( Map.Entry<String, String> entry : prefixes.entrySet() )
{
MapEntryConfig mapEntry = xml.addNewPrefix();
mapEntry.setKey( entry.getKey() );
mapEntry.setValue( entry.getValue() );
}
List<ParticleConfig> particleList = new ArrayList<ParticleConfig>();
for( Particle item : particles )
particleList.add( item.save() );
xml.setParticleArray( particleList.toArray( new ParticleConfig[0] ) );
for( ComplexType item : types.values() )
item.save( xml.addNewComplexType() );
}
/**
* Add a ComplexType to this Schema.
*
* @param type
* The ComplexType to be added.
*/
public void addType( ComplexType type )
{
types.put( type.getName(), type );
type.setSchema( this );
}
/**
* Getter for the namespace of this Schema.
*
* @return The namespace of this Schema.
*/
public String getNamespace()
{
return namespace;
}
/**
* Gets the prefix used in this schema for a different namespace, if one
* exists.
*
* @param namespace
* Another namespace to get the prefix for.
* @return The prefix used for the given namespace.
*/
public String getPrefixForNamespace( String namespace )
{
return prefixes.get( namespace );
}
/**
* Set the prefix used in this schema for a different namespace.
*
* @param prefix
* The prefix to be used.
* @param namespace
* The namespace to use the prefix for.
*/
public void putPrefixForNamespace( String prefix, String namespace )
{
prefixes.put( namespace, prefix );
}
/**
* Get a Type contained in this schema by name.
*
* @param name
* The name of a contained Type.
* @return Returns the Type, if one is found. Otherwise returns null.
*/
public Type getType( String name )
{
return types.get( name );
}
/**
* Create and add a new root element for this schema.
*
* @param name
* The name to give the newly created element.
* @return Returns the newly created element.
*/
public Particle newElement( String name )
{
Particle p = Particle.Factory.newElementInstance( this, name );
particles.add( p );
return p;
}
/**
* Create and add a new global attribute for this schema.
*
* @param name
* The name to give the newly created attribute.
* @return Returns the newly created attribute.
*/
public Particle newAttribute( String name )
{
Particle p = Particle.Factory.newAttributeInstance( this, name );
particles.add( p );
return p;
}
public String toString()
{
StringBuilder s = new StringBuilder( "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + "<"
+ getPrefixForNamespace( Settings.xsdns ) + ":schema " );
if( StringUtils.hasContent( namespace ) )
s.append( "targetNamespace=\"" + namespace + "\" " + "xmlns=\"" + namespace + "\" " );
for( Map.Entry<String, String> entry : prefixes.entrySet() )
s.append( "xmlns:" + entry.getValue() + "=\"" + entry.getKey() + "\" " );
s.append( "elementFormDefault=\"qualified\">" );
for( Particle item : particles )
{
s.append( item );
}
for( Type item : types.values() )
{
s.append( item );
}
if( s.toString().contains( "type=\"" + empty.getName() + "\"" ) )
s.append( empty );
s.append( "</" + getPrefixForNamespace( Settings.xsdns ) + ":schema>" );
return s.toString();
}
/**
* Validates an XML document contained in a given Context object.
*
* @param context
* A Context object containing the XML data to be validated, and
* other needed contextual variables.
* @throws XmlException
* On unresolvable validation error.
*/
public void validate( Context context ) throws XmlException
{
XmlCursor cursor = context.getCursor();
Particle root = getParticle( cursor.getName().getLocalPart() );
if( root == null )
{
if( context.getHandler().callback( Event.CREATION, ConflictHandler.Type.ELEMENT, cursor.getName(),
"/" + cursor.getName().getLocalPart(), "Undeclared root element." ) )
{
root = newElement( cursor.getName().getLocalPart() );
}
else
throw new XmlException( "Illegal root element" );
}
root.validate( context );
}
/**
* Getter for the SchemaSystem that contains this Schema.
*
* @return Returns the parent SchemaSystem.
*/
public SchemaSystem getSystem()
{
return schemaSystem;
}
/**
* Get a global particle by its name.
*
* @param name
* The name of the particle to get.
* @return Returns the Particle if one is found. Otherwise returns null.
*/
public Particle getParticle( String name )
{
for( Particle item : particles )
{
if( item.getName().getLocalPart().equals( name ) )
return item;
}
return null;
}
}