X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-common%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fcommon%2FQName.java;h=0ac89ae8da2c1d634d134bc07977877e5a9c4484;hb=27555bc40477a5db7a6d453f47a589705b2d5362;hp=cfadd8f81959341f85d139e7c7715afce1672ab9;hpb=23df6e207d1dc0c705d50bd0014db7a3ae7d1484;p=yangtools.git diff --git a/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java b/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java index cfadd8f819..0ac89ae8da 100644 --- a/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java +++ b/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java @@ -19,8 +19,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.opendaylight.yangtools.concepts.Immutable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The QName from XML consists of local name of element and XML namespace, but @@ -32,43 +30,46 @@ import org.slf4j.LoggerFactory; * same local name, but from different schemas. * * * + * QName may also have prefix assigned, but prefix does not + * affect equality and identity of two QNames and carry only information + * which may be useful for serializers / deserializers. + * * */ public final class QName implements Immutable, Serializable, Comparable { private static final long serialVersionUID = 5398411242927766414L; - private static final Logger LOGGER = LoggerFactory.getLogger(QName.class); static final String QNAME_REVISION_DELIMITER = "?revision="; static final String QNAME_LEFT_PARENTHESIS = "("; static final String QNAME_RIGHT_PARENTHESIS = ")"; - private static final Pattern QNAME_PATTERN_FULL = Pattern.compile( - "^\\((.+)\\" + QNAME_REVISION_DELIMITER + "(.+)\\)(.+)$"); - private static final Pattern QNAME_PATTERN_NO_REVISION = Pattern.compile( - "^\\((.+)\\)(.+)$"); - private static final Pattern QNAME_PATTERN_NO_NAMESPACE_NO_REVISION = Pattern.compile( - "^(.+)$"); + private static final Pattern QNAME_PATTERN_FULL = Pattern.compile("^\\((.+)\\" + QNAME_REVISION_DELIMITER + + "(.+)\\)(.+)$"); + private static final Pattern QNAME_PATTERN_NO_REVISION = Pattern.compile("^\\((.+)\\)(.+)$"); + private static final Pattern QNAME_PATTERN_NO_NAMESPACE_NO_REVISION = Pattern.compile("^(.+)$"); - private static final char[] ILLEGAL_CHARACTERS = new char[] {'?', '(', ')', '&'}; + private static final char[] ILLEGAL_CHARACTERS = new char[] { '?', '(', ')', '&' }; - //Nullable - private final URI namespace; - //Mandatory + // Mandatory + private final QNameModule module; + // Mandatory private final String localName; - //Nullable + // Nullable private final String prefix; - //Nullable - private final String formattedRevision; - //Nullable - private final Date revision; + + private QName(final QNameModule module, final String prefix, final String localName) { + this.localName = checkLocalName(localName); + this.prefix = prefix; + this.module = module; + } /** * QName Constructor. @@ -81,17 +82,10 @@ public final class QName implements Immutable, Serializable, Comparable { * locally defined prefix assigned to local name * @param localName * YANG schema identifier + * */ public QName(final URI namespace, final Date revision, final String prefix, final String localName) { - this.localName = checkLocalName(localName); - this.namespace = namespace; - this.revision = revision; - this.prefix = prefix; - if(revision != null) { - this.formattedRevision = getRevisionFormat().format(revision); - } else { - this.formattedRevision = null; - } + this(QNameModule.create(namespace, revision), prefix, localName); } /** @@ -114,60 +108,15 @@ public final class QName implements Immutable, Serializable, Comparable { throw new IllegalArgumentException("Parameter 'localName' must be a non-empty string."); } - for (char c: ILLEGAL_CHARACTERS) { + for (char c : ILLEGAL_CHARACTERS) { if (localName.indexOf(c) != -1) { throw new IllegalArgumentException(String.format( - "Parameter 'localName':'%s' contains illegal character '%s'", - localName, c)); + "Parameter 'localName':'%s' contains illegal character '%s'", localName, c)); } } return localName; } - /** - * QName Constructor. - * - * @param namespace - * the namespace assigned to the YANG module - * @param revision - * the revision of the YANG module - * @param localName - * YANG schema identifier - */ - public QName(final URI namespace, final Date revision, final String localName) { - this(namespace, revision, null, localName); - } - - public QName(final QName base, final String localName) { - this(base.getNamespace(), base.getRevision(), base.getPrefix(), localName); - } - - /** - * @deprecated Use {@link #create(String)} instead. - * This implementation is broken. - */ - @Deprecated - public QName(final String input) throws ParseException { - Date revision = null; - String nsAndRev = input.substring(input.indexOf("(") + 1, input.indexOf(")")); - if (nsAndRev.contains("?")) { - String[] splitted = nsAndRev.split("\\?"); - this.namespace = URI.create(splitted[0]); - revision = getRevisionFormat().parse(splitted[1]); - } else { - this.namespace = URI.create(nsAndRev); - } - - this.localName = checkLocalName(input.substring(input.indexOf(")") + 1)); - this.revision = revision; - this.prefix = null; - if (revision != null) { - this.formattedRevision = getRevisionFormat().format(revision); - } else { - this.formattedRevision = null; - } - } - public static QName create(final String input) { Matcher matcher = QNAME_PATTERN_FULL.matcher(input); if (matcher.matches()) { @@ -185,18 +134,27 @@ public final class QName implements Immutable, Serializable, Comparable { matcher = QNAME_PATTERN_NO_NAMESPACE_NO_REVISION.matcher(input); if (matcher.matches()) { String localName = matcher.group(1); - return new QName((URI)null, localName); + return new QName((URI) null, localName); } throw new IllegalArgumentException("Invalid input:" + input); } + /** + * Get the module component of the QName. + * + * @return Module component + */ + public QNameModule getModule() { + return module; + } + /** * Returns XMLNamespace assigned to the YANG module. * * @return XMLNamespace assigned to the YANG module. */ public URI getNamespace() { - return namespace; + return module.getNamespace(); } /** @@ -218,7 +176,7 @@ public final class QName implements Immutable, Serializable, Comparable { * otherwise returns null */ public Date getRevision() { - return revision; + return module.getRevision(); } /** @@ -235,23 +193,30 @@ public final class QName implements Immutable, Serializable, Comparable { final int prime = 31; int result = 1; result = prime * result + ((localName == null) ? 0 : localName.hashCode()); - result = prime * result + ((namespace == null) ? 0 : namespace.hashCode()); - result = prime * result + ((formattedRevision == null) ? 0 : formattedRevision.hashCode()); + result = prime * result + module.hashCode(); return result; } + /** + * + * Compares the specified object with this list for equality. Returns + * true if and only if the specified object is also instance of + * {@link QName} and its {@link #getLocalName()}, {@link #getNamespace()} and + * {@link #getRevision()} are equals to same properties of this instance. + * + * @param o the object to be compared for equality with this QName + * @return true if the specified object is equal to this QName + * + */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } - if (obj == null) { + if (!(obj instanceof QName)) { return false; } - if (getClass() != obj.getClass()) { - return false; - } - QName other = (QName) obj; + final QName other = (QName) obj; if (localName == null) { if (other.localName != null) { return false; @@ -259,51 +224,99 @@ public final class QName implements Immutable, Serializable, Comparable { } else if (!localName.equals(other.localName)) { return false; } - if (namespace == null) { - if (other.namespace != null) { - return false; - } - } else if (!namespace.equals(other.namespace)) { - return false; - } - if (formattedRevision == null) { - if (other.formattedRevision != null) { - return false; - } - } else if (!revision.equals(other.revision)) { - return false; - } - return true; + return module.equals(other.module); } + public static QName create(final QName base, final String localName) { + return new QName(base.getModule(), base.getPrefix(), localName); + } - public static QName create(final QName base, final String localName){ - return new QName(base, localName); + /** + * Creates new QName. + * + * @param qnameModule + * Namespace and revision enclosed as a QNameModule + * @param prefix + * Namespace prefix + * @param localName + * Local name part of QName. MUST NOT BE null. + * @return Instance of QName + */ + public static QName create(final QNameModule module, final String prefix, final String localName) { + if (module == null) { + throw new NullPointerException("module may not be null"); + } + return new QName(module, prefix, localName); } - public static QName create(final URI namespace, final Date revision, final String localName){ - return new QName(namespace, revision, localName); + /** + * Creates new QName. + * + * @param qnameModule + * Namespace and revision enclosed as a QNameModule + * @param localName + * Local name part of QName. MUST NOT BE null. + * @return Instance of QName + */ + public static QName create(final QNameModule qnameModule, final String localName) { + return new QName(qnameModule, null, localName); } + /** + * Creates new QName. + * + * @param namespace + * Namespace of QName or null if namespace is undefined. + * @param revision + * Revision of namespace or null if revision is unspecified. + * @param localName + * Local name part of QName. MUST NOT BE null. + * @return Instance of QName + */ + public static QName create(final URI namespace, final Date revision, final String localName) { + return new QName(QNameModule.create(namespace, revision), null, localName); + } - public static QName create(final String namespace, final String revision, final String localName) throws IllegalArgumentException{ + /** + * + * Creates new QName. + * + * @param namespace + * Namespace of QName, MUST NOT BE Null. + * @param revision + * Revision of namespace / YANG module. MUST NOT BE null, MUST BE + * in format YYYY-mm-dd. + * @param localName + * Local name part of QName. MUST NOT BE null. + * @return + * @throws NullPointerException + * If any of paramaters is null. + * @throws IllegalArgumentException + * If namespace is not valid URI or + * revision is not according to format + * YYYY-mm-dd. + */ + public static QName create(final String namespace, final String revision, final String localName) + throws IllegalArgumentException { + final URI namespaceUri; try { - URI namespaceUri = new URI(namespace); - Date revisionDate = parseRevision(revision); - return create(namespaceUri, revisionDate, localName); - } catch (URISyntaxException ue) { - throw new IllegalArgumentException("Namespace is is not valid URI", ue); + namespaceUri = new URI(namespace); + } catch (URISyntaxException ue) { + throw new IllegalArgumentException(String.format("Namespace '%s' is not a valid URI", namespace), ue); } + + Date revisionDate = parseRevision(revision); + return create(namespaceUri, revisionDate, localName); } @Override public String toString() { StringBuilder sb = new StringBuilder(); - if (namespace != null) { - sb.append(QNAME_LEFT_PARENTHESIS + namespace); + if (getNamespace() != null) { + sb.append(QNAME_LEFT_PARENTHESIS + getNamespace()); - if (revision != null) { - sb.append(QNAME_REVISION_DELIMITER + getRevisionFormat().format(revision)); + if (getFormattedRevision() != null) { + sb.append(QNAME_REVISION_DELIMITER + getFormattedRevision()); } sb.append(QNAME_RIGHT_PARENTHESIS); } @@ -312,62 +325,74 @@ public final class QName implements Immutable, Serializable, Comparable { } /** - * Returns a namespace in form defined by section 5.6.4. of {@link https - * ://tools.ietf.org/html/rfc6020}, if namespace is not correctly defined, - * the method will return null
- * example "http://example.acme.com/system?revision=2008-04-01" + * Return string representation of revision in format + * YYYY-mm-dd * - * @return namespace in form defined by section 5.6.4. of {@link https - * ://tools.ietf.org/html/rfc6020}, if namespace is not correctly - * defined, the method will return null + * YANG Specification defines format for revision as + * YYYY-mm-dd. This format for revision is reused accross multiple places + * such as capabilities URI, YANG modules, etc. * + * @return String representation of revision or null, if revision is not + * set. */ - URI getRevisionNamespace() { - - if (namespace == null) { - return null; - } - - String query = ""; - if (revision != null) { - query = "revision=" + formattedRevision; - } - - URI compositeURI = null; - try { - compositeURI = new URI(namespace.getScheme(), namespace.getUserInfo(), namespace.getHost(), - namespace.getPort(), namespace.getPath(), query, namespace.getFragment()); - } catch (URISyntaxException e) { - LOGGER.error("", e); - } - return compositeURI; - } - public String getFormattedRevision() { - return formattedRevision; + return module.getFormattedRevision(); } + /** + * Creates copy of this with revision and prefix unset. + * + * @return copy of this QName with revision and prefix unset. + */ public QName withoutRevision() { - return QName.create(namespace, null, localName); + return QName.create(getNamespace(), null, localName); } public static Date parseRevision(final String formatedDate) { try { return getRevisionFormat().parse(formatedDate); - } catch (ParseException| RuntimeException e) { - throw new IllegalArgumentException("Revision is not in supported format:" + formatedDate,e); + } catch (ParseException | RuntimeException e) { + throw new IllegalArgumentException( + String.format("Revision '%s'is not in a supported format", formatedDate), e); } } + /** + * Formats {@link Date} representing revision to format + * YYYY-mm-dd + * + * YANG Specification defines format for revision as + * YYYY-mm-dd. This format for revision is reused accross multiple places + * such as capabilities URI, YANG modules, etc. + * + * @param revision + * Date object to format or null + * @return String representation or null if the input was null. + */ public static String formattedRevision(final Date revision) { - if(revision == null) { + if (revision == null) { return null; } return getRevisionFormat().format(revision); } + /** + * + * Compares this QName to other, without comparing revision. + * + * Compares instance of this to other instance of QName and returns true if + * both instances have equal localName ({@link #getLocalName()} + * ) and namespace ({@link #getNamespace()}). + * + * @param other + * Other QName. Must not be null. + * @return true if this instance and other have equals localName and + * namespace. + * @throws NullPointerException + * if other is null. + */ public boolean isEqualWithoutRevision(final QName other) { - return localName.equals(other.getLocalName()) && Objects.equals(namespace, other.getNamespace()); + return localName.equals(other.getLocalName()) && Objects.equals(getNamespace(), other.getNamespace()); } @Override @@ -379,30 +404,30 @@ public final class QName implements Immutable, Serializable, Comparable { } // compare nullable namespace parameter - if (namespace == null) { - if (other.namespace != null) { + if (getNamespace() == null) { + if (other.getNamespace() != null) { return -1; } } else { - if (other.namespace == null) { + if (other.getNamespace() == null) { return 1; } - result = namespace.compareTo(other.namespace); + result = getNamespace().compareTo(other.getNamespace()); if (result != 0) { return result; } } // compare nullable revision parameter - if (revision == null) { - if (other.revision != null) { + if (getRevision() == null) { + if (other.getRevision() != null) { return -1; } } else { - if (other.revision == null) { + if (other.getRevision() == null) { return 1; } - result = revision.compareTo(other.revision); + result = getRevision().compareTo(other.getRevision()); if (result != 0) { return result; }