/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.impl.wadl.inference.schema; 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; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 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; } }