View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 eviware.com
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wadl.inference.schema;
14  
15  import java.util.ArrayList;
16  import java.util.HashMap;
17  import java.util.List;
18  import java.util.Map;
19  
20  import org.apache.xmlbeans.XmlCursor;
21  import org.apache.xmlbeans.XmlException;
22  
23  import com.eviware.soapui.impl.wadl.inference.ConflictHandler;
24  import com.eviware.soapui.impl.wadl.inference.ConflictHandler.Event;
25  import com.eviware.soapui.impl.wadl.inference.schema.types.ComplexType;
26  import com.eviware.soapui.impl.wadl.inference.schema.types.EmptyType;
27  import com.eviware.soapui.inferredSchema.ComplexTypeConfig;
28  import com.eviware.soapui.inferredSchema.MapEntryConfig;
29  import com.eviware.soapui.inferredSchema.ParticleConfig;
30  import com.eviware.soapui.inferredSchema.SchemaConfig;
31  import com.eviware.soapui.support.StringUtils;
32  
33  /***
34   * Represents an inferred schema for a single namespace.
35   * 
36   * @author Dain Nilsson
37   */
38  public class Schema
39  {
40  	private SchemaSystem schemaSystem;
41  	private String namespace;
42  	private Map<String, String> prefixes;
43  	private Map<String, ComplexType> types;
44  	private List<Particle> particles;
45  	private EmptyType empty = new EmptyType( this );
46  
47  	/***
48  	 * Constructs a blank new Schema for the given namespace in the given
49  	 * SchemaSystem.
50  	 * 
51  	 * @param namespace
52  	 *           The namespace for the new schema.
53  	 * @param schemaSystem
54  	 *           The SchemaSystem in which to place the newly created Schema.
55  	 */
56  	public Schema( String namespace, SchemaSystem schemaSystem )
57  	{
58  		this.schemaSystem = schemaSystem;
59  		this.namespace = namespace;
60  		prefixes = new HashMap<String, String>();
61  		particles = new ArrayList<Particle>();
62  		types = new HashMap<String, ComplexType>();
63  		putPrefixForNamespace( "xs", Settings.xsdns );
64  	}
65  
66  	/***
67  	 * Constructs a Schema object using previously saved data.
68  	 * 
69  	 * @param xml
70  	 *           The XmlObject to which data has previously been saved.
71  	 * @param schemaSystem
72  	 *           The SchemaSystem in which to place the newly created Schema.
73  	 */
74  	public Schema( SchemaConfig xml, SchemaSystem schemaSystem )
75  	{
76  		this.schemaSystem = schemaSystem;
77  		namespace = xml.getNamespace();
78  		prefixes = new HashMap<String, String>();
79  		particles = new ArrayList<Particle>();
80  		types = new HashMap<String, ComplexType>();
81  		for( MapEntryConfig entry : xml.getPrefixList() )
82  			prefixes.put( entry.getKey(), entry.getValue() );
83  		for( ParticleConfig item : xml.getParticleList() )
84  		{
85  			particles.add( Particle.Factory.parse( item, this ) );
86  		}
87  		for( ComplexTypeConfig item : xml.getComplexTypeList() )
88  		{
89  			types.put( item.getName(), new ComplexType( item, this ) );
90  		}
91  	}
92  
93  	/***
94  	 * Save the Schema to an XmlObject.
95  	 * 
96  	 * @param xml
97  	 *           A blank XmlObject to save to.
98  	 */
99  	public void save( SchemaConfig xml )
100 	{
101 		xml.setNamespace( namespace );
102 		for( Map.Entry<String, String> entry : prefixes.entrySet() )
103 		{
104 			MapEntryConfig mapEntry = xml.addNewPrefix();
105 			mapEntry.setKey( entry.getKey() );
106 			mapEntry.setValue( entry.getValue() );
107 		}
108 		List<ParticleConfig> particleList = new ArrayList<ParticleConfig>();
109 		for( Particle item : particles )
110 			particleList.add( item.save() );
111 		xml.setParticleArray( particleList.toArray( new ParticleConfig[0] ) );
112 		for( ComplexType item : types.values() )
113 			item.save( xml.addNewComplexType() );
114 	}
115 
116 	/***
117 	 * Add a ComplexType to this Schema.
118 	 * 
119 	 * @param type
120 	 *           The ComplexType to be added.
121 	 */
122 	public void addType( ComplexType type )
123 	{
124 		types.put( type.getName(), type );
125 		type.setSchema( this );
126 	}
127 
128 	/***
129 	 * Getter for the namespace of this Schema.
130 	 * 
131 	 * @return The namespace of this Schema.
132 	 */
133 	public String getNamespace()
134 	{
135 		return namespace;
136 	}
137 
138 	/***
139 	 * Gets the prefix used in this schema for a different namespace, if one
140 	 * exists.
141 	 * 
142 	 * @param namespace
143 	 *           Another namespace to get the prefix for.
144 	 * @return The prefix used for the given namespace.
145 	 */
146 	public String getPrefixForNamespace( String namespace )
147 	{
148 		return prefixes.get( namespace );
149 	}
150 
151 	/***
152 	 * Set the prefix used in this schema for a different namespace.
153 	 * 
154 	 * @param prefix
155 	 *           The prefix to be used.
156 	 * @param namespace
157 	 *           The namespace to use the prefix for.
158 	 */
159 	public void putPrefixForNamespace( String prefix, String namespace )
160 	{
161 		prefixes.put( namespace, prefix );
162 	}
163 
164 	/***
165 	 * Get a Type contained in this schema by name.
166 	 * 
167 	 * @param name
168 	 *           The name of a contained Type.
169 	 * @return Returns the Type, if one is found. Otherwise returns null.
170 	 */
171 	public Type getType( String name )
172 	{
173 		return types.get( name );
174 	}
175 
176 	/***
177 	 * Create and add a new root element for this schema.
178 	 * 
179 	 * @param name
180 	 *           The name to give the newly created element.
181 	 * @return Returns the newly created element.
182 	 */
183 	public Particle newElement( String name )
184 	{
185 		Particle p = Particle.Factory.newElementInstance( this, name );
186 		particles.add( p );
187 		return p;
188 	}
189 
190 	/***
191 	 * Create and add a new global attribute for this schema.
192 	 * 
193 	 * @param name
194 	 *           The name to give the newly created attribute.
195 	 * @return Returns the newly created attribute.
196 	 */
197 	public Particle newAttribute( String name )
198 	{
199 		Particle p = Particle.Factory.newAttributeInstance( this, name );
200 		particles.add( p );
201 		return p;
202 	}
203 
204 	public String toString()
205 	{
206 		StringBuilder s = new StringBuilder( "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + "<"
207 				+ getPrefixForNamespace( Settings.xsdns ) + ":schema " );
208 		
209 		if( StringUtils.hasContent( namespace ))
210 			s.append( "targetNamespace=\"" + namespace + "\" " + "xmlns=\"" + namespace + "\" " );
211 		
212 		
213 		for( Map.Entry<String, String> entry : prefixes.entrySet() )
214 			s.append( "xmlns:" + entry.getValue() + "=\"" + entry.getKey() + "\" " );
215 		s.append( "elementFormDefault=\"qualified\">" );
216 		for( Particle item : particles )
217 		{
218 			s.append( item );
219 		}
220 		for( Type item : types.values() )
221 		{
222 			s.append( item );
223 		}
224 		if( s.toString().contains( "type=\"" + empty.getName() + "\"" ) )
225 			s.append( empty );
226 		s.append( "</" + getPrefixForNamespace( Settings.xsdns ) + ":schema>" );
227 		return s.toString();
228 	}
229 
230 	/***
231 	 * Validates an XML document contained in a given Context object.
232 	 * 
233 	 * @param context
234 	 *           A Context object containing the XML data to be validated, and
235 	 *           other needed contextual variables.
236 	 * @throws XmlException
237 	 *            On unresolvable validation error.
238 	 */
239 	public void validate( Context context ) throws XmlException
240 	{
241 		XmlCursor cursor = context.getCursor();
242 		Particle root = getParticle( cursor.getName().getLocalPart() );
243 		if( root == null )
244 		{
245 			if( context.getHandler().callback( Event.CREATION, ConflictHandler.Type.ELEMENT, cursor.getName(),
246 					"/" + cursor.getName().getLocalPart(), "Undeclared root element." ) )
247 			{
248 				root = newElement( cursor.getName().getLocalPart() );
249 			}
250 			else
251 				throw new XmlException( "Illegal root element" );
252 		}
253 
254 		root.validate( context );
255 	}
256 
257 	/***
258 	 * Getter for the SchemaSystem that contains this Schema.
259 	 * 
260 	 * @return Returns the parent SchemaSystem.
261 	 */
262 	public SchemaSystem getSystem()
263 	{
264 		return schemaSystem;
265 	}
266 
267 	/***
268 	 * Get a global particle by its name.
269 	 * 
270 	 * @param name
271 	 *           The name of the particle to get.
272 	 * @return Returns the Particle if one is found. Otherwise returns null.
273 	 */
274 	public Particle getParticle( String name )
275 	{
276 		for( Particle item : particles )
277 		{
278 			if( item.getName().getLocalPart().equals( name ) )
279 				return item;
280 		}
281 		return null;
282 	}
283 }