2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.common;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.base.Preconditions;
13 import java.io.Externalizable;
14 import java.io.IOException;
15 import java.io.ObjectInput;
16 import java.io.ObjectOutput;
17 import java.io.Serializable;
18 import java.util.Optional;
19 import java.util.regex.Pattern;
20 import javax.annotation.Nonnull;
21 import javax.annotation.Nullable;
22 import javax.annotation.RegEx;
25 * Dedicated object identifying a YANG module revision.
28 * <h3>API design note</h3>
29 * This class defines the contents of a revision statement, but modules do not require to have a revision (e.g. they
30 * have not started to keep track of revisions).
33 * APIs which involve this class should always transfer instances via {@code Optional<Revision>}, which is
34 * the primary bridge data type. Implementations can use nullable fields with explicit conversions to/from
35 * {@link Optional}. Both patterns can take advantage of {@link #compare(Optional, Optional)} and
36 * {@link #compare(Revision, Revision)} respectively.
38 * @author Robert Varga
40 public final class Revision implements Comparable<Revision>, Serializable {
41 private static final long serialVersionUID = 1L;
44 private static final String STRING_FORMAT_PATTERN_STR = "\\d\\d\\d\\d\\-\\d\\d-\\d\\d";
47 * String format pattern, which can be used to match parts of a string into components.
49 public static final Pattern STRING_FORMAT_PATTERN = Pattern.compile(STRING_FORMAT_PATTERN_STR);
51 private final String str;
53 private Revision(final String str) {
54 // Since all strings conform to this format, compareTo() can be delegated to String.compareTo()
55 Preconditions.checkArgument(STRING_FORMAT_PATTERN.matcher(str).matches(),
56 "String '%s' does match revision format YYYY-MM-DD", str);
61 * Parse a revision string.
63 * @param str String to be parsed
64 * @return A Revision instance.
65 * @throws IllegalArgumentException if the string format does not conform specification.
66 * @throws NullPointerException if the string is null
68 public static Revision valueOf(@Nonnull final String str) {
69 return new Revision(str);
73 * Compare two {@link Optional}s wrapping Revisions. Arguments and return value are consistent with
74 * {@link java.util.Comparator#compare(Object, Object)} interface contract. Missing revisions compare as lower
75 * than any other revision.
77 * @param first First optional revision
78 * @param second Second optional revision
79 * @return Positive, zero, or negative integer.
81 public static int compare(final Optional<Revision> first, final Optional<Revision> second) {
82 if (first.isPresent()) {
83 return second.isPresent() ? first.get().compareTo(second.get()) : 1;
85 return second.isPresent() ? -1 : 0;
89 * Compare two explicitly nullable Revisions. Unlike {@link #compareTo(Revision)}, this handles both arguments
90 * being null such that total ordering is defined.
92 * @param first First revision
93 * @param second Second revision
94 * @return Positive, zero, or negative integer.
96 public static int compare(@Nullable final Revision first, @Nullable final Revision second) {
98 return second != null ? first.compareTo(second) : 1;
100 return second != null ? -1 : 0;
104 @SuppressWarnings("checkstyle:parameterName")
105 public int compareTo(final Revision o) {
106 return str.compareTo(o.str);
110 public int hashCode() {
111 return str.hashCode();
115 public boolean equals(final Object obj) {
116 return this == obj || obj instanceof Revision && str.equals(((Revision)obj).str);
120 public String toString() {
124 Object writeReplace() {
125 return new Proxy(str);
128 private static final class Proxy implements Externalizable {
129 private static final long serialVersionUID = 1L;
133 @SuppressWarnings("checkstyle:redundantModifier")
135 // For Externalizable
138 Proxy(final String str) {
139 this.str = requireNonNull(str);
143 public void writeExternal(final ObjectOutput out) throws IOException {
144 out.writeObject(str);
148 public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
149 str = (String) in.readObject();
152 private Object readResolve() {
153 return Revision.valueOf(str);