/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.metamodels.xml.aspects.validation.rules;
import java.util.Iterator;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.jdom.Verifier;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.designer.core.validation.ObjectValidationRule;
import org.teiid.designer.core.validation.ValidationContext;
import org.teiid.designer.core.validation.ValidationProblem;
import org.teiid.designer.core.validation.ValidationProblemImpl;
import org.teiid.designer.core.validation.ValidationResult;
import org.teiid.designer.core.validation.ValidationResultImpl;
import org.teiid.designer.metamodels.xml.XmlDocumentPlugin;
import org.teiid.designer.metamodels.xml.XmlElement;
import org.teiid.designer.metamodels.xml.XmlNamespace;
/**
* AccessPatternColumnsRule
*
* @since 8.0
*/
public class XmlNamespaceRule implements ObjectValidationRule {
final static String XML_NS = "http://www.w3.org/XML/1998/namespace"; //$NON-NLS-1$
final static String XML = "xml"; //$NON-NLS-1$
//These are the return message from the org.jdom.Verifier class
final static String NUMBER_ERR = "Namespace prefixes cannot begin with a number"; //$NON-NLS-1$
final static String DOLLAR_ERR = "Namespace prefixes cannot begin with a dollar sign ($)"; //$NON-NLS-1$
final static String HYPHEN_ERR = "Namespace prefixes cannot begin with a hyphen (-)"; //$NON-NLS-1$
final static String PERIOD_ERR = "Namespace prefixes cannot begin with a period (.)"; //$NON-NLS-1$
final static String COLON_ERR = "Namespace prefixes cannot contain colons"; //$NON-NLS-1$
final static String INVALID_CHAR_ERR = "Namespace prefixes cannot contain the character \""; //$NON-NLS-1$
final static String XML_ERR = "Namespace prefixes cannot begin with \"xml\" in any combination of case"; //$NON-NLS-1$
/*
* @See org.teiid.designer.core.validation.ObjectValidationRule#validate(org.eclipse.emf.ecore.EObject, org.teiid.designer.core.validation.ValidationContext)
*/
@Override
public void validate(EObject eObject, ValidationContext context) {
CoreArgCheck.isInstanceOf(XmlNamespace.class, eObject);
final XmlNamespace ns = (XmlNamespace) eObject;
final String uri = ns.getUri();
final ValidationResult result = new ValidationResultImpl(eObject);
//validate the prefix
validatePrefix(ns, result);
//validate the uri
validateUri(uri, result);
//validete that the element has only one target namespace
validateElement(ns, result);
// Add the results to the context (do this last, because not added to context if there are no results)
context.addResult(result);
}
/**
* @param element
* @param context
*/
private void validateElement(final XmlNamespace ns, final ValidationResult result) {
final XmlElement element = ns.getElement();
if(element == null){
//Element attribute may not be null
final String msg = XmlDocumentPlugin.Util.getString("XmlNamespaceRule.Namespace_Element_attribute_may_not_be_null_1"); //$NON-NLS-1$
final ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR, msg);
result.addProblem(problem);
return;
}
// Find the prefix for this namespace ...
final String nsPrefix = ns.getPrefix();
if(nsPrefix == null || nsPrefix.trim().length() == 0 ) {
// This is a default namespace declaration, so see whether there are other globals ...
final Iterator namespaces = element.getDeclaredNamespaces().iterator();
int numDefaultNamespaceDeclarations = 0;
while(namespaces.hasNext() ){
XmlNamespace next = (XmlNamespace)namespaces.next();
final String prefix = next.getPrefix();
if(prefix == null || prefix.trim().length() == 0 ){
++numDefaultNamespaceDeclarations;
}
}
if(numDefaultNamespaceDeclarations > 1){
// There were more than one, so mark this one with the problem; the others will be marked
// when they are found (again)
final String msg = XmlDocumentPlugin.Util.getString("XmlNamespaceRule.Namespace_Element_may_have_only_no_more_than_one_Namespace_Declaration_with_no_Prefix_(Target_Namespace)_2"); //$NON-NLS-1$
final ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR, msg);
result.addProblem(problem);
}
}
}
/**
* @param uri
* @param context
*/
private void validateUri(String uri, final ValidationResult result) {
//The uri may not be null or zero length
if(uri == null || uri.trim().length() == 0){
final String msg = XmlDocumentPlugin.Util.getString("XmlNamespaceRule.Uri_may_not_be_null_or_zero_length_1"); //$NON-NLS-1$
final ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR, msg);
result.addProblem(problem);
}
}
/**
* @param prefix
*/
private void validatePrefix(final XmlNamespace ns, final ValidationResult result) {
//1. The first character of a XML namespace declaration's prefix, if specified, must be from
// the following set: [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D]
// | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF]
// | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]. (From http://www.w3.org/TR/xml-names11 )
//2. The non-first characters of a XML namespace declaration's prefix, if specified, must be from the
// following set: [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D]
// | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF]
// | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F]
// | [#x203F-#x2040]. (From http://www.w3.org/TR/xml-names11 )
//3. Prefix may not begin with xml (case insensitive)
//4. The "xml" prefix may only be assigned to the uri "http://www.w3.org/XML/1998/namespace"
final String prefix = ns.getPrefix();
if(prefix == null){
return;
}
//1-4 : Use the org.jdom Verifier class to validate the prefix characters
final String errMsg = convertPrefixProblemString(Verifier.checkNamespacePrefix(prefix), ns);
if(errMsg != null){
final ValidationProblem problem = new ValidationProblemImpl(0, IStatus.ERROR, errMsg);
result.addProblem(problem);
}
}
/**
* @param errMsg
*/
private String convertPrefixProblemString(final String errMsg, final XmlNamespace ns) {
if(errMsg == null){
return null;
}
String msg = null;
if(errMsg.equals(NUMBER_ERR) ){
msg = XmlDocumentPlugin.Util.getString("XmlNamespaceRule.Namespace_prefixes_cannot_begin_with_a_number_3"); //$NON-NLS-1$
}else if(errMsg.equals(COLON_ERR) ){
msg = XmlDocumentPlugin.Util.getString("XmlNamespaceRule.Namespace_prefixes_cannot_contain_colons_4"); //$NON-NLS-1$
}else if(errMsg.equals(DOLLAR_ERR) ){
msg = XmlDocumentPlugin.Util.getString("XmlNamespaceRule.Namespace_prefixes_cannot_begin_with_a_dollar_sign_($)_5"); //$NON-NLS-1$
}else if(errMsg.equals(HYPHEN_ERR) ){
msg = XmlDocumentPlugin.Util.getString("XmlNamespaceRule.Namespace_prefixes_cannot_begin_with_a_hyphen_(-)_6"); //$NON-NLS-1$
}else if(errMsg.equals(PERIOD_ERR) ){
msg = XmlDocumentPlugin.Util.getString("XmlNamespaceRule.Namespace_prefixes_cannot_begin_with_a_period_(.)_7"); //$NON-NLS-1$
}else if(errMsg.startsWith(INVALID_CHAR_ERR) ){
final String part1 = XmlDocumentPlugin.Util.getString("XmlNamespaceRule.Namespace_prefixes_cannot_contain_the_character___8"); //$NON-NLS-1$
final String invalidChar = errMsg.substring(49,50);
msg = part1 + invalidChar + "\""; //$NON-NLS-1$
}else if(errMsg.equals(XML_ERR) ){
if(XML_NS.equals(ns.getUri() ) && XML.equals(ns.getPrefix() ) ){
//The ns may be xml as long as the uri = "http://www.w3.org/XML/1998/namespace"
return null;
}
msg = XmlDocumentPlugin.Util.getString("XmlNamespaceRule.Namespace_prefixes_cannot_begin_with___xml___in_any_combination_of_case_9"); //$NON-NLS-1$
}
return msg;
}
}