blob: e3285abc3a2c18d1881a4cf90351b81b8348634d [file] [log] [blame]
/**
* Copyright (c) 2002-2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* IBM - Initial API and implementation
*/
package org.eclipse.xsd.impl;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.xsd.XSDComponent;
import org.eclipse.xsd.XSDCompositor;
import org.eclipse.xsd.XSDConcreteComponent;
import org.eclipse.xsd.XSDConstraint;
import org.eclipse.xsd.XSDDiagnostic;
import org.eclipse.xsd.XSDDiagnosticSeverity;
import org.eclipse.xsd.XSDElementDeclaration;
import org.eclipse.xsd.XSDFactory;
import org.eclipse.xsd.XSDModelGroup;
import org.eclipse.xsd.XSDModelGroupDefinition;
import org.eclipse.xsd.XSDPackage;
import org.eclipse.xsd.XSDParticle;
import org.eclipse.xsd.XSDParticleContent;
import org.eclipse.xsd.XSDPlugin;
import org.eclipse.xsd.XSDSimpleTypeDefinition;
import org.eclipse.xsd.XSDTerm;
import org.eclipse.xsd.XSDTypeDefinition;
import org.eclipse.xsd.XSDWildcard;
import org.eclipse.xsd.util.XSDConstants;
import org.eclipse.xsd.util.XSDSwitch;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>Particle</b></em>'.
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
* </p>
* <ul>
* <li>{@link org.eclipse.xsd.impl.XSDParticleImpl#getMinOccurs <em>Min Occurs</em>}</li>
* <li>{@link org.eclipse.xsd.impl.XSDParticleImpl#getMaxOccurs <em>Max Occurs</em>}</li>
* <li>{@link org.eclipse.xsd.impl.XSDParticleImpl#getContent <em>Content</em>}</li>
* <li>{@link org.eclipse.xsd.impl.XSDParticleImpl#getTerm <em>Term</em>}</li>
* </ul>
*
* @generated
*/
public class XSDParticleImpl
extends XSDComplexTypeContentImpl
implements XSDParticle
{
protected static final int MAXIMUM_STATES = 10000;
/**
* The default value of the '{@link #getMinOccurs() <em>Min Occurs</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getMinOccurs()
* @generated
* @ordered
*/
protected static final int MIN_OCCURS_EDEFAULT = 1;
/**
* The cached value of the '{@link #getMinOccurs() <em>Min Occurs</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getMinOccurs()
* @generated
* @ordered
*/
protected int minOccurs = MIN_OCCURS_EDEFAULT;
/**
* The flag representing whether the Min Occurs attribute has been set.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
* @ordered
*/
protected static final int MIN_OCCURS_ESETFLAG = 1 << 8;
/**
* The default value of the '{@link #getMaxOccurs() <em>Max Occurs</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getMaxOccurs()
* @generated
* @ordered
*/
protected static final int MAX_OCCURS_EDEFAULT = 1;
/**
* The cached value of the '{@link #getMaxOccurs() <em>Max Occurs</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getMaxOccurs()
* @generated
* @ordered
*/
protected int maxOccurs = MAX_OCCURS_EDEFAULT;
/**
* The flag representing whether the Max Occurs attribute has been set.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
* @ordered
*/
protected static final int MAX_OCCURS_ESETFLAG = 1 << 9;
/**
* The cached value of the '{@link #getContent() <em>Content</em>}' containment reference.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getContent()
* @generated
* @ordered
*/
protected XSDParticleContent content;
/**
* The cached value of the '{@link #getTerm() <em>Term</em>}' reference.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getTerm()
* @generated
* @ordered
*/
protected XSDTerm term;
public static XSDParticle createParticle(Node node)
{
XSDParticleContent xsdParticleContent = XSDParticleContentImpl.createParticleContent(node);
if (xsdParticleContent != null)
{
XSDParticle xsdParticle = XSDFactory.eINSTANCE.createXSDParticle();
xsdParticle.setElement((Element)node);
xsdParticle.setContent(xsdParticleContent);
return xsdParticle;
}
return null;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected XSDParticleImpl()
{
super();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass()
{
return XSDPackage.Literals.XSD_PARTICLE;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public int getMinOccurs()
{
return minOccurs;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setMinOccurs(int newMinOccurs)
{
int oldMinOccurs = minOccurs;
minOccurs = newMinOccurs;
boolean oldMinOccursESet = (eFlags & MIN_OCCURS_ESETFLAG) != 0;
eFlags |= MIN_OCCURS_ESETFLAG;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, XSDPackage.XSD_PARTICLE__MIN_OCCURS, oldMinOccurs, minOccurs, !oldMinOccursESet));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void unsetMinOccurs()
{
int oldMinOccurs = minOccurs;
boolean oldMinOccursESet = (eFlags & MIN_OCCURS_ESETFLAG) != 0;
minOccurs = MIN_OCCURS_EDEFAULT;
eFlags &= ~MIN_OCCURS_ESETFLAG;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.UNSET, XSDPackage.XSD_PARTICLE__MIN_OCCURS, oldMinOccurs, MIN_OCCURS_EDEFAULT, oldMinOccursESet));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public boolean isSetMinOccurs()
{
return (eFlags & MIN_OCCURS_ESETFLAG) != 0;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public int getMaxOccurs()
{
return maxOccurs;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setMaxOccurs(int newMaxOccurs)
{
int oldMaxOccurs = maxOccurs;
maxOccurs = newMaxOccurs;
boolean oldMaxOccursESet = (eFlags & MAX_OCCURS_ESETFLAG) != 0;
eFlags |= MAX_OCCURS_ESETFLAG;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, XSDPackage.XSD_PARTICLE__MAX_OCCURS, oldMaxOccurs, maxOccurs, !oldMaxOccursESet));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void unsetMaxOccurs()
{
int oldMaxOccurs = maxOccurs;
boolean oldMaxOccursESet = (eFlags & MAX_OCCURS_ESETFLAG) != 0;
maxOccurs = MAX_OCCURS_EDEFAULT;
eFlags &= ~MAX_OCCURS_ESETFLAG;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.UNSET, XSDPackage.XSD_PARTICLE__MAX_OCCURS, oldMaxOccurs, MAX_OCCURS_EDEFAULT, oldMaxOccursESet));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public boolean isSetMaxOccurs()
{
return (eFlags & MAX_OCCURS_ESETFLAG) != 0;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public XSDParticleContent getContent()
{
return content;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setContent(XSDParticleContent newContent)
{
if (newContent != content)
{
NotificationChain msgs = null;
if (content != null)
msgs = ((InternalEObject)content).eInverseRemove(this, EOPPOSITE_FEATURE_BASE - XSDPackage.XSD_PARTICLE__CONTENT, null, msgs);
if (newContent != null)
msgs = ((InternalEObject)newContent).eInverseAdd(this, EOPPOSITE_FEATURE_BASE - XSDPackage.XSD_PARTICLE__CONTENT, null, msgs);
msgs = basicSetContent(newContent, msgs);
if (msgs != null) msgs.dispatch();
}
else if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, XSDPackage.XSD_PARTICLE__CONTENT, newContent, newContent));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public NotificationChain basicSetContent(XSDParticleContent newContent, NotificationChain msgs)
{
XSDParticleContent oldContent = content;
content = newContent;
if (eNotificationRequired())
{
ENotificationImpl notification = new ENotificationImpl(this, Notification.SET, XSDPackage.XSD_PARTICLE__CONTENT, oldContent, newContent);
if (msgs == null) msgs = notification; else msgs.add(notification);
}
return msgs;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public XSDTerm getTerm()
{
return term;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setTerm(XSDTerm newTerm)
{
XSDTerm oldTerm = term;
term = newTerm;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, XSDPackage.XSD_PARTICLE__TERM, oldTerm, term));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs)
{
switch (featureID)
{
case XSDPackage.XSD_PARTICLE__CONTENT:
return basicSetContent(null, msgs);
}
return super.eInverseRemove(otherEnd, featureID, msgs);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType)
{
switch (featureID)
{
case XSDPackage.XSD_PARTICLE__MIN_OCCURS:
return getMinOccurs();
case XSDPackage.XSD_PARTICLE__MAX_OCCURS:
return getMaxOccurs();
case XSDPackage.XSD_PARTICLE__CONTENT:
return getContent();
case XSDPackage.XSD_PARTICLE__TERM:
return getTerm();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eSet(int featureID, Object newValue)
{
switch (featureID)
{
case XSDPackage.XSD_PARTICLE__MIN_OCCURS:
setMinOccurs((Integer)newValue);
return;
case XSDPackage.XSD_PARTICLE__MAX_OCCURS:
setMaxOccurs((Integer)newValue);
return;
case XSDPackage.XSD_PARTICLE__CONTENT:
setContent((XSDParticleContent)newValue);
return;
case XSDPackage.XSD_PARTICLE__TERM:
setTerm((XSDTerm)newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eUnset(int featureID)
{
switch (featureID)
{
case XSDPackage.XSD_PARTICLE__MIN_OCCURS:
unsetMinOccurs();
return;
case XSDPackage.XSD_PARTICLE__MAX_OCCURS:
unsetMaxOccurs();
return;
case XSDPackage.XSD_PARTICLE__CONTENT:
setContent((XSDParticleContent)null);
return;
case XSDPackage.XSD_PARTICLE__TERM:
setTerm((XSDTerm)null);
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean eIsSet(int featureID)
{
switch (featureID)
{
case XSDPackage.XSD_PARTICLE__MIN_OCCURS:
return isSetMinOccurs();
case XSDPackage.XSD_PARTICLE__MAX_OCCURS:
return isSetMaxOccurs();
case XSDPackage.XSD_PARTICLE__CONTENT:
return content != null;
case XSDPackage.XSD_PARTICLE__TERM:
return term != null;
}
return super.eIsSet(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public String toString()
{
if (eIsProxy()) return super.toString();
StringBuffer result = new StringBuffer(super.toString());
result.append(" (minOccurs: ");
if ((eFlags & MIN_OCCURS_ESETFLAG) != 0) result.append(minOccurs); else result.append("<unset>");
result.append(", maxOccurs: ");
if ((eFlags & MAX_OCCURS_ESETFLAG) != 0) result.append(maxOccurs); else result.append("<unset>");
result.append(')');
return result.toString();
}
@Override
public Element createElement()
{
Element newElement = null;
XSDParticleContent theContent = getContent();
if (theContent != null)
{
newElement = ((XSDConcreteComponentImpl)theContent).createElement();
setElement(newElement);
}
return newElement;
}
@Override
protected void patch()
{
super.patch();
patchHelper();
}
protected void patchHelper()
{
XSDParticleContent theContent = getContent();
XSDTerm newTerm = null;
if (theContent instanceof XSDModelGroupDefinition)
{
XSDModelGroupDefinition xsdModelGroupDefinition = (XSDModelGroupDefinition)theContent;
newTerm = xsdModelGroupDefinition.getResolvedModelGroupDefinition().getModelGroup();
}
else if (theContent instanceof XSDElementDeclaration)
{
XSDElementDeclaration xsdElementDeclaration = (XSDElementDeclaration)theContent;
newTerm = xsdElementDeclaration.getResolvedElementDeclaration();
}
else
{
newTerm = (XSDTerm)theContent;
}
if (getTerm() != newTerm)
{
setTerm(newTerm);
}
}
@Override
public boolean analyze()
{
xsdNFA = null;
return super.analyze();
}
@Override
public void validate()
{
super.validate();
if (getMaxOccurs() != -1)
{
if (getMinOccurs() > getMaxOccurs())
{
createDiagnostic(XSDDiagnosticSeverity.ERROR_LITERAL, "coss-particle.2.1");
}
}
}
@Override
protected Collection<Element> getContentNodes(Element changedElement)
{
return Collections.singleton(getElement());
}
@Override
protected void reconcileAttributes(Element changedElement)
{
super.reconcileAttributes(changedElement);
if (changedElement == getElement())
{
if (changedElement.hasAttributeNS(null, XSDConstants.MINOCCURS_ATTRIBUTE))
{
String newMinOccurs = changedElement.getAttributeNS(null, XSDConstants.MINOCCURS_ATTRIBUTE);
try
{
int newMinOccursValue = Integer.parseInt(newMinOccurs);
if (!isSetMinOccurs() || newMinOccursValue != getMinOccurs())
{
setMinOccurs(newMinOccursValue);
}
}
catch (NumberFormatException exception)
{
// Ignore
}
}
else if (isSetMinOccurs())
{
unsetMinOccurs();
}
if (changedElement.hasAttributeNS(null, XSDConstants.MAXOCCURS_ATTRIBUTE))
{
String newMaxOccurs = changedElement.getAttributeNS(null, XSDConstants.MAXOCCURS_ATTRIBUTE);
try
{
int newMaxOccursValue = "unbounded".equals(newMaxOccurs) ? -1 : Integer.parseInt(newMaxOccurs);
if (!isSetMaxOccurs() || newMaxOccursValue != getMaxOccurs())
{
setMaxOccurs(newMaxOccursValue);
}
}
catch (NumberFormatException exception)
{
// Ignore
}
}
else if (isSetMaxOccurs())
{
unsetMaxOccurs();
}
XSDParticleContent theContent = getContent();
if (theContent != null)
{
theContent.elementAttributesChanged(changedElement);
}
}
}
@Override
protected void reconcileContents(Element changedElement)
{
super.reconcileContents(changedElement);
XSDParticleContent theContent = getContent();
if (theContent != null)
{
theContent.elementContentsChanged(changedElement);
XSDTerm newTerm =
(XSDTerm)
new XSDSwitch<Object>()
{
@Override
public Object caseXSDElementDeclaration(XSDElementDeclaration xsdElementDeclaration)
{
return xsdElementDeclaration.getResolvedElementDeclaration();
}
@Override
public Object caseXSDModelGroupDefinition(XSDModelGroupDefinition xsdModelGroupDefinition)
{
return xsdModelGroupDefinition.getResolvedModelGroupDefinition().getModelGroup();
}
@Override
public Object caseXSDWildcard(XSDWildcard xsdWildcard)
{
return xsdWildcard;
}
@Override
public Object caseXSDModelGroup(XSDModelGroup xsdModelGroup)
{
return xsdModelGroup;
}
}.doSwitch(theContent);
if (newTerm != getTerm())
{
setTerm(newTerm);
}
}
}
@Override
protected void changeAttribute(EAttribute eAttribute)
{
if (isReconciling)
{
return;
}
super.changeAttribute(eAttribute);
Element theElement = getElement();
if (theElement != null)
{
if (eAttribute == null || eAttribute == XSDPackage.Literals.XSD_PARTICLE__MIN_OCCURS)
{
niceSetAttribute
(theElement,
XSDConstants.MINOCCURS_ATTRIBUTE,
isSetMinOccurs() ? Integer.toString(getMinOccurs()) : null);
}
if (eAttribute == null || eAttribute == XSDPackage.Literals.XSD_PARTICLE__MAX_OCCURS)
{
niceSetAttribute
(theElement,
XSDConstants.MAXOCCURS_ATTRIBUTE,
isSetMaxOccurs() ? getMaxOccurs() == -1 ? "unbounded" : Integer.toString(getMaxOccurs()) : null);
}
}
}
@Override
protected void adoptContent(EReference eReference, XSDConcreteComponent xsdConcreteComponent)
{
super.adoptContent(eReference, xsdConcreteComponent);
if (eReference == XSDPackage.Literals.XSD_PARTICLE__CONTENT)
{
patchHelper();
traverseToRootForPatching();
}
}
@Override
protected void orphanContent(EReference eReference, XSDConcreteComponent xsdConcreteComponent)
{
super.orphanContent(eReference, xsdConcreteComponent);
if (eReference == XSDPackage.Literals.XSD_PARTICLE__CONTENT)
{
patchHelper();
traverseToRootForPatching();
}
}
public static class XSDNFA implements XSDParticle.DFA
{
private static final class StateList extends BasicEList<State>
{
private static final long serialVersionUID = 1L;
public StateList()
{
super();
}
public StateList(Collection<State> states)
{
super(states);
}
@Override
protected Object [] newData(int capacity)
{
return new StateImpl [capacity];
}
@Override
protected final boolean useEquals()
{
return false;
}
@Override
public boolean contains(Object object)
{
for (int i = 0; i < size; ++i)
{
if (data[i] == object)
{
return true;
}
}
return false;
}
@Override
public void clear()
{
Object [] oldData = data;
super.clear();
data = oldData;
}
@SuppressWarnings("unchecked")
@Override
public <T> T[] toArray(T[] array)
{
if (array == EMPTY_STATE_ARRAY)
{
return (T[])data;
}
else
{
return super.toArray(array);
}
}
}
private static final class TransitionList extends UniqueEList<Transition>
{
private static final long serialVersionUID = 1L;
Set<XSDParticle.DFA.Transition> set = new HashSet<XSDParticle.DFA.Transition>();
@Override
protected Object[] newData(int capacity)
{
return new TransitionImpl [capacity];
}
@Override
public boolean addAll(Collection<? extends Transition> collection)
{
boolean result = false;
Transition [] transitions = collection.toArray(EMPTY_TRANSITION_ARRAY);
int collectionSize = collection.size();
grow(size + collectionSize);
for (int i = 0; i < collectionSize; ++i)
{
Transition transition = transitions[i];
if (set.add(transition))
{
data[size++] = transition;
result = true;
}
}
return result;
}
@Override
protected void didAdd(int index, Transition newObject)
{
set.add(newObject);
}
@Override
protected void didRemove(int index, Transition oldObject)
{
set.remove(oldObject);
}
@Override
protected void didClear(int size, Object[] oldObjects)
{
set.clear();
}
@Override
public boolean contains(Object object)
{
return set.contains(object);
}
@Override
public void clear()
{
Object [] oldData = data;
super.clear();
data = oldData;
}
@SuppressWarnings("unchecked")
@Override
public <T> T[] toArray(T[] array)
{
if (array == EMPTY_TRANSITION_ARRAY)
{
return (T[])data;
}
else
{
return super.toArray(array);
}
}
}
public static class StateImpl implements XSDParticle.DFA.State
{
protected UniqueEList<XSDParticle.DFA.Transition> transitions;
protected boolean isAccepting;
public StateImpl()
{
transitions = new TransitionList();
}
public List<XSDParticle.DFA.Transition> getTransitions()
{
return transitions;
}
public boolean isAccepting()
{
return isAccepting;
}
public void setAccepting(boolean isAccepting)
{
this.isAccepting = isAccepting;
}
protected TransitionImpl createdTransition;
public XSDParticle.DFA.Transition createTransition(XSDParticle xsdParticle, XSDParticle.DFA.State state)
{
if (createdTransition == null)
{
createdTransition = new TransitionImpl(xsdParticle, state);
}
else
{
createdTransition.setParticle(xsdParticle);
createdTransition.setState(state);
}
if (transitions.add(createdTransition))
{
XSDParticle.DFA.Transition result = createdTransition;
createdTransition = null;
return result;
}
else
{
return null;
}
}
public XSDParticle.DFA.Transition accept(String namespaceURI, String localName)
{
for (Transition transition : getTransitions())
{
XSDParticle xsdParticle = transition.getParticle();
XSDTerm xsdTerm = xsdParticle.getTerm();
if (xsdTerm instanceof XSDElementDeclaration)
{
XSDElementDeclaration xsdElementDeclaration = (XSDElementDeclaration)xsdTerm;
if ((namespaceURI == null ?
xsdElementDeclaration.getTargetNamespace() == null :
namespaceURI.equals(xsdElementDeclaration.getTargetNamespace())) &&
localName.equals(xsdElementDeclaration.getName()))
{
return transition;
}
}
else if (xsdTerm instanceof XSDWildcard)
{
XSDWildcard xsdWildcard = (XSDWildcard)xsdTerm;
if (xsdWildcard.allows(namespaceURI))
{
return transition;
}
}
}
return null;
}
}
public static class TransitionImpl implements XSDParticle.DFA.Transition
{
protected XSDParticle xsdParticle;
protected XSDParticle.DFA.State state;
protected int hashCode;
public TransitionImpl(XSDParticle xsdParticle, XSDParticle.DFA.State state)
{
this.xsdParticle = xsdParticle;
this.state = state;
hashCode = -1;
}
public final XSDParticle.DFA.State getState()
{
return state;
}
public void setState(XSDParticle.DFA.State state)
{
this.state = state;
hashCode = -1;
}
public final XSDParticle getParticle()
{
return xsdParticle;
}
public void setParticle(XSDParticle xsdParticle)
{
this.xsdParticle = xsdParticle;
hashCode = -1;
}
@Override
public int hashCode()
{
if (hashCode == -1)
{
hashCode = (xsdParticle == null ? 0 : xsdParticle.hashCode()) ^ (state == null ? 0 : state.hashCode());
}
return hashCode;
}
@Override
public boolean equals(Object that)
{
if (that instanceof TransitionImpl)
{
TransitionImpl otherTransition = (TransitionImpl)that;
return
xsdParticle == otherTransition.xsdParticle &&
state == otherTransition.state;
}
else
{
return false;
}
}
}
private static final StateImpl[] EMPTY_STATE_ARRAY = new StateImpl [0];
private static final TransitionImpl[] EMPTY_TRANSITION_ARRAY = new TransitionImpl [0];
protected List<State> states = new StateList();
protected StateImpl initialState;
protected StateImpl finalState;
protected XSDParticle xsdParticle;
protected StateImpl currentState;
protected Set<XSDModelGroup> visitedModelGroups;
protected Collection<XSDDiagnostic> diagnostics;
protected boolean isApproximate;
protected XSDNFA(boolean isApproximate)
{
this.isApproximate = isApproximate;
currentState = initialState = createState(null);
finalState = createState(null);
}
protected XSDNFA(Set<XSDModelGroup> visitedModelGroups, XSDParticle xsdParticle, XSDTerm xsdTerm, boolean isApproximate)
{
this.isApproximate = isApproximate;
this.visitedModelGroups = visitedModelGroups;
this.xsdParticle = xsdParticle;
currentState = initialState = createState(null);
finalState = createState(xsdTerm);
if (!visitedModelGroups.contains(xsdTerm))
{
initialize(xsdTerm);
}
}
public XSDNFA(Set<XSDModelGroup> visitedModelGroups, XSDParticle xsdParticle, boolean isApproximate)
{
this.isApproximate = isApproximate;
this.visitedModelGroups = visitedModelGroups;
this.xsdParticle = xsdParticle;
currentState = initialState = createState(null);
finalState = createState(xsdParticle);
initialize(xsdParticle);
}
public XSDNFA(XSDParticle xsdParticle, boolean isApproximate)
{
this.isApproximate = isApproximate;
this.visitedModelGroups = new HashSet<XSDModelGroup>();
this.xsdParticle = xsdParticle;
currentState = initialState = createState(null);
finalState = createState(xsdParticle);
initialize(xsdParticle);
}
protected void checkBadTransitions()
{
for (State state : getStates())
{
for (Transition transition : state.getTransitions())
{
if (!getStates().contains(transition.getState()))
{
Thread.dumpStack();
}
}
}
}
protected XSDNFA(XSDNFA original, boolean isApproximate)
{
this.isApproximate = isApproximate;
xsdParticle = original.getParticle();
Map<State, State> stateCloneMap = new HashMap<State, State>();
List<State> originalStates = original.getStates();
for (int i = 0, size = originalStates.size(); i < size; ++i)
{
State originalState = originalStates.get(i);
StateImpl clonedState = createState(null);
stateCloneMap.put(originalState, clonedState);
clonedState.setAccepting(originalState.isAccepting());
}
currentState = initialState = (StateImpl)stateCloneMap.get(original.getInitialState());
finalState = (StateImpl)stateCloneMap.get(original.getFinalState());
for (int i = 0, size = originalStates.size(); i < size; ++i)
{
State originalState = originalStates.get(i);
List<Transition> originalTransitions = originalState.getTransitions();
for (int j = 0, transitionSize = originalTransitions.size(); j < transitionSize; ++j)
{
Transition originalTransition = originalTransitions.get(j);
((StateImpl)stateCloneMap.get(originalState)).createTransition
(originalTransition.getParticle(), stateCloneMap.get(originalTransition.getState()));
}
}
}
protected StateImpl createState(XSDComponent associatedComponent)
{
StateImpl result = new StateImpl();
states.add(result);
return result;
}
protected void initialize(XSDComponent xsdComponent)
{
if (xsdComponent instanceof XSDElementDeclaration)
{
XSDElementDeclaration xsdElementDeclaration = (XSDElementDeclaration)xsdComponent;
for (XSDElementDeclaration substititonGroupMember : xsdElementDeclaration.getSubstitutionGroup())
{
if (substititonGroupMember == xsdElementDeclaration)
{
initialState.createTransition(xsdParticle, finalState);
}
else
{
XSDParticle substititonGroupMemberParticle = ((XSDParticleImpl)xsdParticle).getXSDFactory().createXSDParticle();
substititonGroupMemberParticle.setTerm(substititonGroupMember);
initialState.createTransition(substititonGroupMemberParticle, finalState);
}
}
}
else if (xsdComponent instanceof XSDWildcard)
{
initialState.createTransition(xsdParticle, finalState);
}
else if (xsdComponent instanceof XSDModelGroup)
{
XSDModelGroup xsdModelGroup = (XSDModelGroup)xsdComponent;
visitedModelGroups.add(xsdModelGroup);
switch (xsdModelGroup.getCompositor().getValue())
{
case XSDCompositor.SEQUENCE:
{
StateImpl previousState = initialState;
for (XSDParticle xsdParticle : xsdModelGroup.getParticles())
{
XSDNFA particleNFA = new XSDNFA(visitedModelGroups, xsdParticle, isApproximate);
propagateStates(particleNFA);
previousState.createTransition(null, particleNFA.getInitialState());
previousState = (StateImpl)particleNFA.getFinalState();
if (getStates().size() > MAXIMUM_STATES)
{
break;
}
}
previousState.createTransition(null, finalState);
break;
}
case XSDCompositor.CHOICE:
{
for (XSDParticle xsdParticle : xsdModelGroup.getParticles())
{
XSDNFA particleNFA = new XSDNFA(visitedModelGroups, xsdParticle, isApproximate);
propagateStates(particleNFA);
initialState.createTransition(null, particleNFA.getInitialState());
((StateImpl)particleNFA.getFinalState()).createTransition(null, finalState);
if (getStates().size() > MAXIMUM_STATES)
{
break;
}
}
break;
}
case XSDCompositor.ALL:
default:
{
if (visitedModelGroups.size() > 1)
{
if (diagnostics == null)
{
diagnostics = new ArrayList<XSDDiagnostic>();
}
XSDDiagnostic xsdDiagnostic = XSDFactory.eINSTANCE.createXSDDiagnostic();
xsdDiagnostic.setSeverity(XSDDiagnosticSeverity.ERROR_LITERAL);
xsdDiagnostic.setMessage
(XSDPlugin.INSTANCE.getString
("_UI_XSDError_message",
new Object []
{
populateDiagnostic(xsdDiagnostic, "cos-all-limited.1", null)
}));
diagnostics.add(xsdDiagnostic);
}
if (xsdModelGroup.getParticles().size() == 0)
{
initialState.createTransition(null, finalState);
}
else
{
List<XSDNFA> particleNFAs = new ArrayList<XSDNFA>(xsdModelGroup.getParticles().size());
for (XSDParticle xsdParticle : xsdModelGroup.getParticles())
{
XSDNFA newParticleNFA = new XSDNFA(visitedModelGroups, xsdParticle, isApproximate);
particleNFAs.add(newParticleNFA);
if (getStates().size() > MAXIMUM_STATES)
{
break;
}
}
if (xsdModelGroup.getParticles().size() > 4)
{
// diagnostics = new ArrayList();
// XSDDiagnostic xsdDiagnostic = XSDFactory.eINSTANCE.createXSDDiagnostic();
// xsdDiagnostic.setSeverity(XSDDiagnosticSeverity.ERROR_LITERAL);
// xsdDiagnostic.setMessage
// (XSDPlugin.INSTANCE.getString
// ("_UI_XSDError_message",
// new Object []
// {
// XSDPlugin.INSTANCE.getString
// ("coss-particle.0.2", new Object [] { xsdModelGroup.getParticles().size() })
// }));
// diagnostics.add(xsdDiagnostic);
isApproximate = true;
// Treat it like a repeating choice.
//
for (XSDParticle xsdParticle : xsdModelGroup.getParticles())
{
XSDNFA particleNFA = new XSDNFA(visitedModelGroups, xsdParticle, isApproximate);
propagateStates(particleNFA);
initialState.createTransition(null, particleNFA.getInitialState());
((StateImpl)particleNFA.getFinalState()).createTransition(null, finalState);
((StateImpl)particleNFA.getFinalState()).createTransition(null, initialState);
if (getStates().size() > MAXIMUM_STATES)
{
break;
}
}
}
else
{
XSDNFA xsdNFA = createPermutations(xsdModelGroup.getParticles(), particleNFAs, new HashMap<List<XSDParticle>, XSDNFA>());
propagateStates(xsdNFA);
initialState.createTransition(null, xsdNFA.getInitialState());
((StateImpl)xsdNFA.getFinalState()).createTransition(null, finalState);
}
}
break;
}
}
visitedModelGroups.remove(xsdModelGroup);
}
else if (xsdComponent instanceof XSDParticle)
{
XSDParticle xsdParticle = (XSDParticle)xsdComponent;
int minOccurs = xsdParticle.getMinOccurs();
int maxOccurs = xsdParticle.getMaxOccurs();
int count = maxOccurs == -1 || isApproximate ? minOccurs : maxOccurs;
if (minOccurs <= count)
{
List<XSDNFA> termNFAs = new ArrayList<XSDNFA>(count);
XSDNFA firstTermNFA = new XSDNFA(visitedModelGroups, xsdParticle, xsdParticle.getTerm(), isApproximate);
propagateStates(firstTermNFA);
termNFAs.add(firstTermNFA);
for (int i = 2; i <= count; ++i)
{
XSDNFA clonedTermNFA = new XSDNFA(firstTermNFA, isApproximate);
propagateStates(clonedTermNFA);
termNFAs.add(clonedTermNFA);
if (getStates().size() > MAXIMUM_STATES)
{
break;
}
}
//XSDNFA previousTermNFA = firstTermNFA;
StateImpl previousState = initialState;
int i;
if (minOccurs == 0)
{
initialState.createTransition(null, firstTermNFA.getInitialState());
initialState.createTransition(null, firstTermNFA.getFinalState());
previousState = (StateImpl)firstTermNFA.getFinalState();
i = 2;
}
else
{
for (i = 1; i <= minOccurs; ++i)
{
XSDNFA termNFA = termNFAs.get(i - 1);
previousState.createTransition(null, termNFA.getInitialState());
previousState = (StateImpl)termNFA.getFinalState();
if (getStates().size() > MAXIMUM_STATES)
{
break;
}
}
}
if (maxOccurs == -1 || isApproximate)
{
previousState.createTransition(null, firstTermNFA.getInitialState());
}
else
{
for ( ; i <= maxOccurs; ++i)
{
XSDNFA termNFA = termNFAs.get(i - 1);
previousState.createTransition(null, termNFA.getInitialState());
((StateImpl)termNFA.getInitialState()).createTransition(null, finalState);
previousState = (StateImpl)termNFA.getFinalState();
if (getStates().size() > MAXIMUM_STATES)
{
break;
}
}
}
previousState.createTransition(null, finalState);
}
}
}
protected XSDNFA createPermutations(List<XSDParticle> particles, List<XSDNFA> particleNFAs, Map<List<XSDParticle>, XSDNFA> particlesToNFAMap)
{
XSDNFA result = particlesToNFAMap.get(particles);
if (result == null)
{
int size = particleNFAs.size();
if (size == 1)
{
result = new XSDNFA(particleNFAs.get(0), isApproximate);
particlesToNFAMap.put(particles, result);
}
else
{
result = new XSDNFA(isApproximate);
List<XSDNFA> otherParticleNFAs = new ArrayList<XSDNFA>(size - 1);
List<XSDParticle> otherParticles = new ArrayList<XSDParticle>(size - 1);
for (int i = 0; i < size; ++i)
{
XSDNFA particleNFA = particleNFAs.get(i);
XSDParticle particle = particles.get(i);
otherParticleNFAs.clear();
otherParticles.clear();
for (int j = 0; j < size; ++j)
{
XSDParticle otherParticle = particles.get(j);
if (particle != otherParticle)
{
XSDNFA otherParticleNFA = particleNFAs.get(j);
otherParticleNFAs.add(otherParticleNFA);
otherParticles.add(otherParticle);
}
}
XSDNFA clonedParticleNFA = new XSDNFA(particleNFA, isApproximate);
result.propagateStates(clonedParticleNFA);
((StateImpl)result.getInitialState()).createTransition(null, clonedParticleNFA.getInitialState());
XSDNFA combinationXSDNFA = createPermutations
(otherParticles,
otherParticleNFAs,
particlesToNFAMap);
result.propagateStates(combinationXSDNFA);
((StateImpl)clonedParticleNFA.getFinalState()).createTransition(null, combinationXSDNFA.getInitialState());
((StateImpl)combinationXSDNFA.getFinalState()).createTransition(null, result.getFinalState());
}
if (result.getStates().size() > 50)
{
result.epsilonClosure();
result.minimize();
result.determinize();
result.minimize();
result.createFinalState();
}
}
particlesToNFAMap.put(particles, result);
}
return result;
}
public boolean isApproximate()
{
return isApproximate;
}
public List<State> getStates()
{
return states;
}
public XSDParticle.DFA.State getInitialState()
{
return initialState;
}
public XSDParticle.DFA.State getFinalState()
{
return finalState;
}
public XSDParticle getParticle()
{
return xsdParticle;
}
public static String getComponentLabel(Collection<XSDComponent> xsdComponents)
{
StringBuffer result = new StringBuffer();
result.append("{");
for (Iterator<XSDComponent> i = xsdComponents.iterator(); i.hasNext(); )
{
XSDComponent xsdComponent = i.next();
result.append(getComponentLabel(xsdComponent));
if (i.hasNext())
{
result.append(" ");
}
}
result.append("}");
return result.toString();
}
public static String getComponentLabel(XSDComponent xsdComponent)
{
if (xsdComponent == null)
{
return "-";
}
else if (xsdComponent instanceof XSDElementDeclaration)
{
XSDElementDeclaration xsdElementDeclaration = (XSDElementDeclaration)xsdComponent;
return xsdElementDeclaration.getName();
}
else if (xsdComponent instanceof XSDWildcard)
{
XSDWildcard xsdWildcard = (XSDWildcard)xsdComponent;
return xsdWildcard.getStringNamespaceConstraint();
}
else if (xsdComponent instanceof XSDModelGroup)
{
XSDModelGroup xsdModelGroup = (XSDModelGroup)xsdComponent;
switch (xsdModelGroup.getCompositor().getValue())
{
case XSDCompositor.SEQUENCE:
{
return "<sequence/>";
}
case XSDCompositor.CHOICE:
{
return "<choice/>";
}
case XSDCompositor.ALL:
default:
{
return "<all/>";
}
}
}
else if (xsdComponent instanceof XSDParticle)
{
XSDParticle xsdParticle = (XSDParticle)xsdComponent;
return getComponentLabel(xsdParticle.getTerm()) + "[" + xsdParticle.getMinOccurs() + "," + xsdParticle.getMaxOccurs() + "]";
}
else
{
return xsdComponent.toString();
}
}
public void dump(PrintStream out)
{
List<State> stateList = new StateList(getStates());
stateList.remove(initialState);
stateList.add(0, initialState);
if (finalState != null)
{
stateList.remove(finalState);
stateList.add(finalState);
}
out.println
("Component: " + getComponentLabel(xsdParticle) +
" [" + stateList.indexOf(initialState) + ", " +
stateList.indexOf(finalState) + "]");
for (State state : stateList)
{
out.println
(" State: " + stateList.indexOf(state) + (state.isAccepting() ? " *" : ""));
for (Transition transition : state.getTransitions())
{
out.println
(" --> : " + getComponentLabel(transition.getParticle()) + " -> " + stateList.indexOf(transition.getState()));
}
}
}
public void epsilonClosure()
{
finalState.setAccepting(true);
boolean closed;
StateImpl[] statesArray = states.toArray(EMPTY_STATE_ARRAY);
int statesSize = states.size();
Set<Transition> nullTransitions = new HashSet<Transition>();
do
{
closed = true;
for (int i = 0; i < statesSize; ++i)
{
StateImpl state = statesArray[i];
List<Transition> stateTransitions = state.getTransitions();
TransitionImpl [] stateTransitionsArray = stateTransitions.toArray(EMPTY_TRANSITION_ARRAY);
for (int j = 0; j < stateTransitions.size(); ++j)
{
TransitionImpl transition = stateTransitionsArray[j];
if (transition.getParticle() == null)
{
stateTransitions.remove(j);
--j;
closed = false;
State otherState = transition.getState();
if (state != otherState && nullTransitions.add(transition))
{
if (otherState.isAccepting())
{
state.setAccepting(true);
}
stateTransitions.addAll(otherState.getTransitions());
}
stateTransitionsArray = stateTransitions.toArray(EMPTY_TRANSITION_ARRAY);
}
}
nullTransitions.clear();
}
}
while (!closed);
}
public void createFinalState()
{
finalState = createState(null);
for (int i = 0, iSize = states.size(); i < iSize; ++i)
{
StateImpl state = (StateImpl)states.get(i);
if (state.isAccepting())
{
state.setAccepting(false);
state.createTransition(null, finalState);
}
}
}
protected TransitionImpl testTransition = new TransitionImpl(null, null);
public boolean isEquivalent(XSDParticle.DFA.State s1, XSDParticle.DFA.State s2)
{
if (s1.isAccepting() != s2.isAccepting() || s1.getTransitions().size() != s2.getTransitions().size())
{
return false;
}
else
{
List<Transition> stateTransitions = s1.getTransitions();
TransitionImpl[] stateTransitionsArray = stateTransitions.toArray(EMPTY_TRANSITION_ARRAY);
for (int i = 0, iSize = stateTransitions.size(); i < iSize; ++i)
{
TransitionImpl transition = stateTransitionsArray[i];
testTransition.setParticle(transition.getParticle());
testTransition.setState(transition.getState());
if (!s2.getTransitions().contains(testTransition))
{
return false;
}
}
return true;
}
}
public void minimize()
{
int size = states.size();
StateImpl [] theStates = states.toArray(new StateImpl[size]);
StateList equivalentStates = new StateList();
equivalentStates.grow(size);
boolean minimal;
do
{
minimal = true;
for (int i = 0; i < theStates.length; ++i)
{
StateImpl state = theStates[i];
if (state != null)
{
for (int j = i + 1; j < theStates.length; ++j)
{
State otherState = theStates[j];
if (otherState != null && isEquivalent(state, otherState))
{
equivalentStates.add(otherState);
theStates[j] = null;
}
}
if (!equivalentStates.isEmpty())
{
for (int j = 0; j < theStates.length; ++j)
{
State otherState = theStates[j];
if (otherState != null)
{
List<Transition> theTransitions = otherState.getTransitions();
TransitionImpl[] theTransitionsArray = theTransitions.toArray(EMPTY_TRANSITION_ARRAY);
if (equivalentStates.contains(otherState))
{
for (int k = 0, kSize = theTransitions.size(); k < kSize; ++k)
{
TransitionImpl transition = theTransitionsArray[k];
State outgoingState = transition.getState();
if (equivalentStates.contains(outgoingState))
{
state.createTransition(transition.getParticle(), state);
}
else
{
state.createTransition(transition.getParticle(), outgoingState);
}
}
}
else
{
for (int k = theTransitions.size(); --k >= 0; )
{
TransitionImpl transition = theTransitionsArray[k];
State outgoingState = transition.getState();
if (equivalentStates.contains(outgoingState))
{
theTransitions.remove(k);
theTransitions.add(new TransitionImpl(transition.getParticle(), state));
}
}
}
}
}
states.removeAll(equivalentStates);
equivalentStates.clear();
minimal = false;
}
}
}
}
while (!minimal);
}
protected XSDElementDeclaration [] xsdElementDeclarations;
public int checksum()
{
int result = 0;
if (xsdElementDeclarations != null)
{
for (int i = 0, length = xsdElementDeclarations.length; i < length; ++i)
{
result += xsdElementDeclarations[i].getSubstitutionGroup().hashCode();
}
}
else
{
List<XSDElementDeclaration> elements = new UniqueEList.FastCompare<XSDElementDeclaration>();
StateImpl[] statesArray = states.toArray(EMPTY_STATE_ARRAY);
for (int i = 0, iSize = states.size(); i < iSize; ++i)
{
StateImpl state = statesArray[i];
List<Transition> theTransitions = state.getTransitions();
TransitionImpl[] transitionsArray = theTransitions.toArray(EMPTY_TRANSITION_ARRAY);
for (int j = 0, jSize = theTransitions.size(); j < jSize; ++j)
{
TransitionImpl transition = transitionsArray[j];
XSDTerm xsdTerm = transition.getParticle().getTerm();
if (xsdTerm instanceof XSDElementDeclaration)
{
XSDElementDeclaration xsdElementDeclaration = (XSDElementDeclaration)xsdTerm;
if (elements.add(xsdElementDeclaration))
{
result += xsdElementDeclaration.getSubstitutionGroup().hashCode();
}
}
}
}
xsdElementDeclarations = new XSDElementDeclaration[elements.size()];
elements.toArray(xsdElementDeclarations);
}
return result;
}
public void determinize()
{
Set<Set<State>> stateSubsets = new HashSet<Set<State>>();
State originalInitialState = initialState;
Set<State> initialStateSubset = Collections.<State>singleton(initialState);
stateSubsets.add(initialStateSubset);
states.clear();
currentState = initialState = createState(null);
initialState.setAccepting(originalInitialState.isAccepting());
finalState = null;
xsdParticle = null;
Map<Set<State>, State> stateSubsetToStateMap = new HashMap<Set<State>, State>();
stateSubsetToStateMap.put(initialStateSubset, initialState);
List<Transition> transitions = new TransitionList();
do
{
Iterator<Set<State>> s = stateSubsets.iterator();
Set<State> stateSubset = s.next();
s.remove();
StateImpl newState = (StateImpl)stateSubsetToStateMap.get(stateSubset);
transitions.clear();
for (State originalState : stateSubset)
{
transitions.addAll(originalState.getTransitions());
}
TransitionImpl [] transitionsArray = transitions.toArray(EMPTY_TRANSITION_ARRAY);
int count = transitions.size();
while (count > 0)
{
TransitionImpl originalTransition = transitionsArray[0];
int moveIndex = 0;
int index = 1;
XSDParticle particle = originalTransition.getParticle();
State orginalTransitionState = originalTransition.getState();
Set<State> newStateSubset = new HashSet<State>();
newStateSubset.add(orginalTransitionState);
boolean isAccepting = orginalTransitionState.isAccepting();
while (index < count)
{
TransitionImpl otherOriginalTransition = transitionsArray[index++];
if (otherOriginalTransition.getParticle() == particle)
{
State otherOriginalTransitionState = otherOriginalTransition.getState();
newStateSubset.add(otherOriginalTransitionState);
if (otherOriginalTransitionState.isAccepting())
{
isAccepting = true;
}
}
else
{
// Shift it forward to the next unused slot for subsequent processing.
//
transitionsArray[moveIndex++] = otherOriginalTransition;
}
}
count = moveIndex;
StateImpl newNextState = (StateImpl)stateSubsetToStateMap.get(newStateSubset);
if (newNextState == null)
{
newNextState = createState(null);
if (isAccepting)
{
newNextState.setAccepting(true);
}
stateSubsetToStateMap.put(newStateSubset, newNextState);
stateSubsets.add(newStateSubset);
}
else
{
if (newNextState.isAccepting() != isAccepting)
{
Thread.dumpStack();
}
}
newState.createTransition(particle, newNextState);
}
}
while (!stateSubsets.isEmpty());
}
public XSDDiagnostic checkOverlap(XSDTerm xsdComponent1, XSDTerm xsdComponent2)
{
if (xsdComponent1 instanceof XSDElementDeclaration)
{
XSDElementDeclaration xsdElementDeclaration1 = (XSDElementDeclaration)xsdComponent1;
return checkOverlap(xsdElementDeclaration1, xsdComponent2);
}
else if (xsdComponent1 instanceof XSDWildcard)
{
XSDWildcard xsdWildcard1 = (XSDWildcard)xsdComponent1;
return checkOverlap(xsdWildcard1, xsdComponent2);
}
else
{
return null;
}
}
protected XSDDiagnostic checkOverlap(XSDElementDeclaration xsdElementDeclaration1, XSDTerm xsdComponent2)
{
if (xsdComponent2 instanceof XSDElementDeclaration)
{
XSDElementDeclaration xsdElementDeclaration2 = (XSDElementDeclaration)xsdComponent2;
if (xsdElementDeclaration1.hasSameNameAndTargetNamespace(xsdElementDeclaration2))
{
XSDDiagnostic xsdDiagnostic = XSDFactory.eINSTANCE.createXSDDiagnostic();
xsdDiagnostic.setSeverity(XSDDiagnosticSeverity.ERROR_LITERAL);
xsdDiagnostic.setMessage
(XSDPlugin.INSTANCE.getString
("_UI_XSDError_message",
new Object []
{
populateDiagnostic
(xsdDiagnostic, "key-overlap.1", new Object [] { xsdElementDeclaration1.getURI() })
}));
return xsdDiagnostic;
}
}
else if (xsdComponent2 instanceof XSDWildcard)
{
XSDWildcard xsdWildcard2 = (XSDWildcard)xsdComponent2;
if (xsdWildcard2.allows(xsdElementDeclaration1.getTargetNamespace()))
{
XSDDiagnostic xsdDiagnostic = XSDFactory.eINSTANCE.createXSDDiagnostic();
xsdDiagnostic.setSeverity(XSDDiagnosticSeverity.ERROR_LITERAL);
xsdDiagnostic.setMessage
(XSDPlugin.INSTANCE.getString
("_UI_XSDError_message",
new Object []
{
populateDiagnostic(xsdDiagnostic, "key-overlap.2", new Object [] { xsdElementDeclaration1.getURI() })
}));
return xsdDiagnostic;
}
}
return null;
}
protected XSDDiagnostic checkOverlap(XSDWildcard xsdWildcard1, XSDTerm xsdComponent2)
{
if (xsdComponent2 instanceof XSDElementDeclaration)
{
XSDElementDeclaration xsdElementDeclaration2 = (XSDElementDeclaration)xsdComponent2;
if (xsdWildcard1.allows(xsdElementDeclaration2.getTargetNamespace()))
{
XSDDiagnostic xsdDiagnostic = XSDFactory.eINSTANCE.createXSDDiagnostic();
xsdDiagnostic.setSeverity(XSDDiagnosticSeverity.ERROR_LITERAL);
xsdDiagnostic.setMessage
(XSDPlugin.INSTANCE.getString
("_UI_XSDError_message",
new Object []
{
populateDiagnostic(xsdDiagnostic, "key-overlap.2", new Object [] { xsdElementDeclaration2.getURI() })
}));
return xsdDiagnostic;
}
}
else if (xsdComponent2 instanceof XSDWildcard)
{
XSDWildcard xsdWildcard2 = (XSDWildcard)xsdComponent2;
XSDWildcard intersection = xsdWildcard1.attributeWildcardIntersection(xsdWildcard2);
if (intersection != null && !intersection.getNamespaceConstraint().isEmpty())
{
XSDDiagnostic xsdDiagnostic = XSDFactory.eINSTANCE.createXSDDiagnostic();
xsdDiagnostic.setSeverity(XSDDiagnosticSeverity.ERROR_LITERAL);
xsdDiagnostic.setMessage
(XSDPlugin.INSTANCE.getString
("_UI_XSDError_message",
new Object []
{
populateDiagnostic(xsdDiagnostic, "key-overlap.3", new Object [] { intersection.getNamespaceConstraint().get(0) })
}));
return xsdDiagnostic;
}
}
return null;
}
public void propagateStates(XSDNFA xsdNFA)
{
states.addAll(xsdNFA.getStates());
if (xsdNFA.diagnostics != null)
{
if (diagnostics == null)
{
diagnostics = new ArrayList<XSDDiagnostic>();
}
diagnostics.addAll(xsdNFA.diagnostics);
}
}
public Collection<XSDDiagnostic> getDiagnostics()
{
if (diagnostics == null)
{
diagnostics = new ArrayList<XSDDiagnostic>();
Map<String, XSDTypeDefinition> elementURIToTypeMap = new HashMap<String, XSDTypeDefinition>();
int iSize = states.size();
if (iSize > MAXIMUM_STATES)
{
XSDDiagnostic xsdDiagnostic = XSDFactory.eINSTANCE.createXSDDiagnostic();
xsdDiagnostic.setSeverity(XSDDiagnosticSeverity.WARNING_LITERAL);
xsdDiagnostic.setMessage
(XSDPlugin.INSTANCE.getString
("_UI_XSDError_message",
new Object []
{
populateDiagnostic(xsdDiagnostic, "coss-particle.0.1", new Object [] { getStates().size() })
}));
diagnostics.add(xsdDiagnostic);
}
else
{
StateImpl [] statesArray = states.toArray(EMPTY_STATE_ARRAY);
Map<String, XSDElementDeclaration> uriToElementMap = new HashMap<String, XSDElementDeclaration>();
for (int i = 0; i < iSize; ++i)
{
StateImpl state = statesArray[i];
List<Transition> transitions = state.getTransitions();
TransitionImpl[] transitionsArray = transitions.toArray(EMPTY_TRANSITION_ARRAY);
int jSize = transitions.size();
uriToElementMap.clear();
for (int j = 0; j < jSize; ++j)
{
TransitionImpl transition = transitionsArray[j];
XSDTerm xsdTerm = transition.getParticle().getTerm();
if (xsdTerm instanceof XSDElementDeclaration)
{
XSDElementDeclaration xsdElementDeclaration = (XSDElementDeclaration)xsdTerm;
XSDTypeDefinition xsdTypeDefinition = xsdElementDeclaration.getTypeDefinition();
Object otherXSDTypeDefinition = elementURIToTypeMap.put(xsdElementDeclaration.getURI(), xsdTypeDefinition);
if (otherXSDTypeDefinition != null && otherXSDTypeDefinition != xsdTypeDefinition)
{
XSDDiagnostic xsdDiagnostic = XSDFactory.eINSTANCE.createXSDDiagnostic();
xsdDiagnostic.setSeverity(XSDDiagnosticSeverity.ERROR_LITERAL);
xsdDiagnostic.setMessage
(XSDPlugin.INSTANCE.getString
("_UI_XSDError_message",
new Object []
{
populateDiagnostic
(xsdDiagnostic,
"cos-element-consistent",
new Object []
{
xsdElementDeclaration.getURI(),
xsdTypeDefinition.getURI(),
((XSDTypeDefinition)otherXSDTypeDefinition).getURI()
})
}));
diagnostics.add(xsdDiagnostic);
}
if (jSize > 1)
{
XSDElementDeclaration otherXSDElementDeclaration = uriToElementMap.put(xsdElementDeclaration.getURI(), xsdElementDeclaration);
if (otherXSDElementDeclaration != null)
{
XSDDiagnostic xsdDiagnostic = checkOverlap(xsdElementDeclaration, otherXSDElementDeclaration);
if (xsdDiagnostic != null)
{
diagnostics.add(xsdDiagnostic);
}
}
}
}
}
// Only if there are wildcards do the check for overlapping wildcards.
//
if (jSize > 1 && uriToElementMap.size() <= jSize)
{
for (int j = 0; j < jSize; ++j)
{
TransitionImpl transition = transitionsArray[j];
XSDTerm xsdTerm = transition.getParticle().getTerm();
if (xsdTerm instanceof XSDWildcard)
{
XSDWildcard xsdWildcard = (XSDWildcard)xsdTerm;
for (int k = j + 1; k < jSize; ++k)
{
TransitionImpl otherTransition = transitionsArray[k];
XSDDiagnostic xsdDiagnostic = checkOverlap(xsdWildcard, otherTransition.getParticle().getTerm());
if (xsdDiagnostic != null)
{
diagnostics.add(xsdDiagnostic);
}
}
}
}
}
}
}
}
return diagnostics;
}
public XSDParticle.DFA.State getCurrentState()
{
return currentState;
}
public void reset()
{
currentState = initialState;
}
public XSDParticle.DFA cloneDFA()
{
return new XSDNFA(this, isApproximate);
}
}
public static final boolean debug = false;
protected XSDNFA xsdNFA;
protected int xsdNFACheckSum;
public XSDParticle.DFA getDFA()
{
if (xsdNFA == null || (!getSchema().getSchemaForSchemaNamespace().equals(getSchema().getTargetNamespace()) && xsdNFACheckSum != xsdNFA.checksum()))
{
XSDNFA localNFA = new XSDNFA(this, false);
if (localNFA.getStates().size() > MAXIMUM_STATES)
{
localNFA = new XSDNFA(this, true);
}
if (localNFA.getStates().size() < MAXIMUM_STATES)
{
if (debug)
{
System.out.println("-- NFA initial --");
localNFA.dump(System.out);
System.out.println("-- NFA no-epsilon --");
}
localNFA.epsilonClosure();
if (debug)
{
localNFA.dump(System.out);
System.out.println("-- NFA minimal --");
}
localNFA.minimize();
if (debug)
{
localNFA.dump(System.out);
System.out.println("-- DFA --");
}
localNFA.determinize();
if (debug)
{
localNFA.dump(System.out);
System.out.println("-- DFA minimal--");
}
localNFA.minimize();
if (debug)
{
localNFA.dump(System.out);
}
}
else
{
// Clean up bad transitions.
//
for (DFA.State state : localNFA.getStates())
{
for (Iterator<DFA.Transition> j = state.getTransitions().iterator(); j.hasNext(); )
{
DFA.Transition transition = j.next();
if (transition.getParticle() == null)
{
j.remove();
}
}
}
}
xsdNFA = localNFA;
}
return xsdNFA;
}
public boolean isEmptiable()
{
return getDFA().getInitialState().isAccepting();
}
public boolean isSubset(XSDParticle otherParticle)
{
return isSubset(otherParticle, false);
}
public boolean isSubset(XSDParticle otherParticle, boolean diagnose)
{
XSDNFA subset = (XSDNFA)getDFA();
XSDNFA superSet = (XSDNFA)otherParticle.getDFA();
if (!subset.getDiagnostics().isEmpty() || !superSet.getDiagnostics().isEmpty())
{
return true;
}
final Set<List<DFA.State>> states = new HashSet<List<DFA.State>>();
Map<DFA.State, Object> map =
new HashMap<DFA.State, Object>()
{
private static final long serialVersionUID = 1L;
@Override
public Object put(DFA.State key, Object value)
{
DFA.State s1 = key;
DFA.State s2 = (DFA.State)value;
if (s1.isAccepting() && !s2.isAccepting())
{
return null;
}
@SuppressWarnings("unchecked") Set<DFA.State> set = (Set<DFA.State>)super.get(key);
if (set == null)
{
set = new HashSet<DFA.State>();
super.put(key, set);
}
if (set.add(s2))
{
List<DFA.State> pair = new ArrayList<DFA.State>(2);
pair.add(s1);
pair.add(s2);
states.add(pair);
}
return set;
}
};
boolean result = false;
if (map.put(subset.getInitialState(), superSet.getInitialState()) != null)
{
Map<XSDElementDeclaration, XSDElementDeclaration> elementMap = new HashMap<XSDElementDeclaration, XSDElementDeclaration>();
result = true;
LOOP: while (!states.isEmpty())
{
Iterator<List<DFA.State>> iterator = states.iterator();
List<DFA.State> pair = iterator.next();
iterator.remove();
DFA.State substate = pair.get(0);
DFA.State superState = pair.get(1);
for (DFA.Transition subtransition : substate.getTransitions())
{
XSDTerm subXSDTerm = subtransition.getParticle().getTerm();
boolean transitionResult = false;
if (subXSDTerm instanceof XSDElementDeclaration)
{
XSDElementDeclaration subXSDElementDeclaration = (XSDElementDeclaration)subXSDTerm;
for (DFA.Transition superTransition : superState.getTransitions())
{
XSDTerm superXSDTerm = superTransition.getParticle().getTerm();
if (superXSDTerm instanceof XSDElementDeclaration)
{
XSDElementDeclaration superXSDElementDeclaration = (XSDElementDeclaration)superXSDTerm;
if (superXSDElementDeclaration.hasSameNameAndTargetNamespace(subXSDElementDeclaration))
{
if (map.put(subtransition.getState(), superTransition.getState()) != null)
{
elementMap.put(subXSDElementDeclaration, superXSDElementDeclaration);
transitionResult = true;
break;
}
else
{
result = false;
break LOOP;
}
}
}
else
{
XSDWildcard superXSDWildcard = (XSDWildcard)superXSDTerm;
if (superXSDWildcard.allows(subXSDElementDeclaration.getTargetNamespace()))
{
if (map.put(subtransition.getState(), superTransition.getState()) != null)
{
transitionResult = true;
break;
}
else
{
result = false;
break LOOP;
}
}
}
}
}
else
{
XSDWildcard subXSDWildcard = (XSDWildcard)subXSDTerm;
for (DFA.Transition superTransition : superState.getTransitions())
{
XSDTerm superXSDTerm = superTransition.getParticle().getTerm();
if (superXSDTerm instanceof XSDWildcard)
{
XSDWildcard superXSDWildcard = (XSDWildcard)superXSDTerm;
if (subXSDWildcard.isWildcardSubset(superXSDWildcard))
{
if (map.put(subtransition.getState(), superTransition.getState()) != null)
{
transitionResult = true;
break;
}
else
{
result = false;
break LOOP;
}
}
}
}
}
if (!transitionResult)
{
result = false;
break LOOP;
}
}
}
if (result)
{
for (Map.Entry<XSDElementDeclaration, XSDElementDeclaration> entry : elementMap.entrySet())
{
XSDElementDeclaration subXSDElementDeclaration = entry.getKey();
XSDElementDeclaration superXSDElementDeclaration = entry.getValue();
if (superXSDElementDeclaration.isNillable() && !subXSDElementDeclaration.isNillable())
{
result = false;
if (diagnose)
{
getDiagnosticTarget(subXSDElementDeclaration).createDiagnostic
(XSDDiagnosticSeverity.ERROR_LITERAL,
"rcase-NameAndTypeOK.2",
subXSDElementDeclaration.getURI());
}
else
{
break;
}
}
if (superXSDElementDeclaration.getTypeDefinition() instanceof XSDSimpleTypeDefinition)
{
if (superXSDElementDeclaration.getConstraint() == XSDConstraint.FIXED_LITERAL &&
superXSDElementDeclaration.getLexicalValue() != null &&
(subXSDElementDeclaration.getConstraint() != XSDConstraint.FIXED_LITERAL ||
!((XSDSimpleTypeDefinition)superXSDElementDeclaration.getTypeDefinition()).equalLiterals
(superXSDElementDeclaration.getElement(), superXSDElementDeclaration.getLexicalValue(), subXSDElementDeclaration.getElement(), subXSDElementDeclaration.getLexicalValue())))
{
result = false;
if (diagnose)
{
getDiagnosticTarget(subXSDElementDeclaration).createDiagnostic
(XSDDiagnosticSeverity.ERROR_LITERAL,
"rcase-NameAndTypeOK.4",
subXSDElementDeclaration.getLexicalValue(),
subXSDElementDeclaration.getURI());
}
else
{
break;
}
}
}
if (!subXSDElementDeclaration.getDisallowedSubstitutions().containsAll
(superXSDElementDeclaration.getDisallowedSubstitutions()))
{
result = false;
if (diagnose)
{
getDiagnosticTarget(subXSDElementDeclaration).createDiagnostic
(XSDDiagnosticSeverity.ERROR_LITERAL,
"rcase-NameAndTypeOK.6",
subXSDElementDeclaration.getURI());
}
else
{
break;
}
}
XSDTypeDefinition badType =
subXSDElementDeclaration.getTypeDefinition().getBadTypeDerivation
(superXSDElementDeclaration.getTypeDefinition(), false, true);
if (badType != null)
{
result = false;
if (diagnose)
{
getDiagnosticTarget(subXSDElementDeclaration).createDiagnostic
(XSDDiagnosticSeverity.ERROR_LITERAL,
"rcase-NameAndTypeOK.7",
subXSDElementDeclaration.getURI(),
superXSDElementDeclaration.getTypeDefinition().getURI());
}
else
{
break;
}
}
}
}
}
// if (!result)
// {
// printDFA(subset);
// printDFA(superSet);
// }
return result;
}
@Override
public XSDConcreteComponent cloneConcreteComponent(boolean deep, boolean shareDOM)
{
XSDParticleImpl clonedParticle =
(XSDParticleImpl)getXSDFactory().createXSDParticle();
clonedParticle.isReconciling = true;
if (isSetMinOccurs())
{
clonedParticle.setMinOccurs(getMinOccurs());
}
if (isSetMaxOccurs())
{
clonedParticle.setMaxOccurs(getMaxOccurs());
}
clonedParticle.setContent((XSDParticleContent)getContent().cloneConcreteComponent(deep, shareDOM));
if (shareDOM && getElement() != null)
{
clonedParticle.setElement(getElement());
}
clonedParticle.isReconciling = shareDOM;
return clonedParticle;
}
}