com.sun.msv.verifier.identity.IDConstraintChecker 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.verifier.identity;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.relaxng.datatype.Datatype;
import org.xml.sax.ErrorHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import com.sun.msv.grammar.xmlschema.ElementDeclExp;
import com.sun.msv.grammar.xmlschema.IdentityConstraint;
import com.sun.msv.grammar.xmlschema.KeyRefConstraint;
import com.sun.msv.grammar.xmlschema.XMLSchemaGrammar;
import com.sun.msv.util.LightStack;
import com.sun.msv.util.StartTagInfo;
import com.sun.msv.verifier.Acceptor;
import com.sun.msv.verifier.ErrorInfo;
import com.sun.msv.verifier.ValidityViolation;
import com.sun.msv.verifier.Verifier;
import com.sun.msv.verifier.regexp.xmlschema.XSREDocDecl;
/**
* Verifier with XML Schema-related enforcement.
*
*
* This class can be used in the same way as {@link Verifier}.
* This class also checks XML Schema's identity constraint.
*
* @author Kohsuke KAWAGUCHI
*/
public class IDConstraintChecker extends Verifier {
public IDConstraintChecker( XMLSchemaGrammar grammar, ErrorHandler errorHandler ) {
super(new XSREDocDecl(grammar),errorHandler);
this.grammar = grammar;
}
/** the grammar object against which we are validating. */
protected final XMLSchemaGrammar grammar;
/** active mathcers. */
protected final Vector matchers = new Vector();
protected void add( Matcher matcher ) {
matchers.add(matcher);
}
protected void remove( Matcher matcher ) {
matchers.remove(matcher);
}
/**
* a map from SelectorMatcher
to set of KeyValue
s.
*
* One SelectorMatcher correponds to one scope of the identity constraint.
*/
private final Map keyValues = new java.util.HashMap();
/**
* a map from keyref SelectorMatcher
to key/unique
* SelectorMatcher
.
*
* Given a keyref scope, this map stores which key scope should it refer to.
*/
private final Map referenceScope = new java.util.HashMap();
/**
* a map from IdentityConstraint
to a LightStack
of
* SelectorMatcher
.
*
* Each stack top keeps the currently active scope for the given IdentityConstraint.
*/
private final Map activeScopes = new java.util.HashMap();
protected SelectorMatcher getActiveScope( IdentityConstraint c ) {
LightStack s = (LightStack)activeScopes.get(c);
if(s==null) return null;
if(s.size()==0) return null;
return (SelectorMatcher)s.top();
}
protected void pushActiveScope( IdentityConstraint c, SelectorMatcher matcher ) {
LightStack s = (LightStack)activeScopes.get(c);
if(s==null)
activeScopes.put(c,s=new LightStack());
s.push(matcher);
}
protected void popActiveScope( IdentityConstraint c, SelectorMatcher matcher ) {
LightStack s = (LightStack)activeScopes.get(c);
if(s==null)
// since it's trying to pop, there must be a non-empty stack.
throw new Error();
if(s.pop()!=matcher)
// trying to pop a non-active scope.
throw new Error();
}
/**
* adds a new KeyValue to the value set.
* @return true if this is a new value.
*/
protected boolean addKeyValue( SelectorMatcher scope, KeyValue value ) {
Set keys = (Set)keyValues.get(scope);
if(keys==null)
keyValues.put(scope, keys = new java.util.HashSet());
return keys.add(value);
}
/**
* gets the all KeyValue
s that were added within the specified scope.
*/
protected KeyValue[] getKeyValues( SelectorMatcher scope ) {
Set keys = (Set)keyValues.get(scope);
if(keys==null)
return new KeyValue[0];
return (KeyValue[])keys.toArray(new KeyValue[keys.size()]);
}
public void startDocument() throws SAXException {
super.startDocument();
keyValues.clear();
}
public void endDocument() throws SAXException {
super.endDocument();
// keyref check
Map.Entry[] scopes = (Map.Entry[])
keyValues.entrySet().toArray(new Map.Entry[keyValues.size()]);
if(com.sun.msv.driver.textui.Debug.debug)
System.out.println("key/keyref check: there are "+keyValues.size()+" scope(s)");
for( int i=0; i=0; i-- ) {
// Matcher may remove itself from the vector.
// Therefore, to make it work correctly, we have to
// enumerate Matcher in reverse direction.
((Matcher)matchers.get(i)).endElement( dt );
}
}
/** reports an error. */
protected void reportError( ErrorInfo ei, String propKey, Object[] args ) throws SAXException {
// use the current location.
reportError( getLocator(), ei, propKey, args );
}
protected void reportError( Locator loc, ErrorInfo ei, String propKey, Object[] args ) throws SAXException {
hadError = true;
errorHandler.error( new ValidityViolation( loc,
localizeMessage(propKey,args), ei ) );
}
public static String localizeMessage( String propertyName, Object arg ) {
return localizeMessage( propertyName, new Object[]{arg} );
}
public static String localizeMessage( String propertyName, Object[] args ) {
String format = java.util.ResourceBundle.getBundle(
"com.sun.msv.verifier.identity.Messages").getString(propertyName);
return java.text.MessageFormat.format(format, args );
}
public static final String ERR_UNMATCHED_KEY_FIELD =
"IdentityConstraint.UnmatchedKeyField"; // arg :3
public static final String ERR_NOT_UNIQUE =
"IdentityConstraint.NotUnique"; // arg:2
public static final String ERR_NOT_UNIQUE_DIAG =
"IdentityConstraint.NotUnique.Diag"; // arg:2
public static final String ERR_DOUBLE_MATCH =
"IdentityConstraint.DoubleMatch"; // arg:3
public static final String ERR_UNDEFINED_KEY =
"IdentityConstraint.UndefinedKey"; // arg:2
}