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_STR = "\\d\\d\\d\\d\\-\\d\\d-\\d\\d";
45 private static final Pattern STRING_FORMAT = Pattern.compile(STRING_FORMAT_STR);
47 private final String str;
49 private Revision(final String str) {
50 // Since all strings conform to this format, compareTo() can be delegated to String.compareTo()
51 Preconditions.checkArgument(STRING_FORMAT.matcher(str).matches(),
52 "String '%s' does match revision format YYYY-MM-DD", str);
57 * Parse a revision string.
59 * @param str String to be parsed
60 * @return A Revision instance.
61 * @throws IllegalArgumentException if the string format does not conform specification.
62 * @throws NullPointerException if the string is null
64 public static Revision valueOf(@Nonnull final String str) {
65 return new Revision(str);
69 * Compare two {@link Optional}s wrapping Revisions. Arguments and return value are consistent with
70 * {@link java.util.Comparator#compare(Object, Object)} interface contract. Missing revisions compare as lower
71 * than any other revision.
73 * @param first First optional revision
74 * @param second Second optional revision
75 * @return Positive, zero, or negative integer.
77 public static int compare(final Optional<Revision> first, final Optional<Revision> second) {
78 if (first.isPresent()) {
79 return second.isPresent() ? first.get().compareTo(second.get()) : 1;
81 return second.isPresent() ? -1 : 0;
85 * Compare two explicitly nullable Revisions. Unlike {@link #compareTo(Revision)}, this handles both arguments
86 * being null such that total ordering is defined.
88 * @param first First revision
89 * @param second Second revision
90 * @return Positive, zero, or negative integer.
92 public static int compare(@Nullable final Revision first, @Nullable final Revision second) {
94 return second != null ? first.compareTo(second) : 1;
96 return second != null ? -1 : 0;
100 @SuppressWarnings("checkstyle:parameterName")
101 public int compareTo(final Revision o) {
102 return str.compareTo(o.str);
106 public int hashCode() {
107 return str.hashCode();
111 public boolean equals(final Object obj) {
112 return this == obj || obj instanceof Revision && str.equals(((Revision)obj).str);
116 public String toString() {
120 Object writeReplace() {
121 return new Proxy(str);
124 private static final class Proxy implements Externalizable {
125 private static final long serialVersionUID = 1L;
129 @SuppressWarnings("checkstyle:redundantModifier")
131 // For Externalizable
134 Proxy(final String str) {
135 this.str = requireNonNull(str);
139 public void writeExternal(final ObjectOutput out) throws IOException {
140 out.writeObject(str);
144 public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
145 str = (String) in.readObject();
148 private Object readResolve() {
149 return Revision.valueOf(str);