BUG-8123: be better at guessing identifiers
[yangtools.git] / yang / yang-model-api / src / main / java / org / opendaylight / yangtools / yang / model / repo / api / RevisionSourceIdentifier.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.model.repo.api;
9
10 import static org.opendaylight.yangtools.yang.common.YangConstants.RFC6020_YANG_FILE_EXTENSION;
11
12 import com.google.common.annotations.Beta;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import java.text.ParseException;
16 import java.util.AbstractMap.SimpleImmutableEntry;
17 import java.util.Map.Entry;
18 import java.util.Objects;
19 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
20
21 /**
22  * YANG Schema revision source identifier
23  *
24  * Simple transfer object represents revision identifier of source for YANG
25  * schema (module or submodule), which consists of
26  * <ul>
27  * <li>YANG schema name ({@link #getName()}
28  * <li>Module revision (optional) ({link {@link #getRevision()})
29  * </ul>
30  *
31  * Revision source identifier is designated to be carry only necessary
32  * information to look-up YANG model source and to be used by various
33  * SchemaSourceProviders.
34  *
35  * <b>Note:</b>On source retrieval layer it is impossible to distinguish between
36  * YANG module and/or submodule unless source is present.
37  *
38  * <p>
39  * (For further reference see: http://tools.ietf.org/html/rfc6020#section-5.2
40  * and http://tools.ietf.org/html/rfc6022#section-3.1 ).
41  */
42 @Beta
43 public final class RevisionSourceIdentifier extends SourceIdentifier {
44     private static final long serialVersionUID = 1L;
45
46     /**
47      *
48      * Creates new YANG Schema revision source identifier for sources without
49      * a revision.
50      *
51      * @param name
52      *            Name of schema
53      */
54     RevisionSourceIdentifier(final String name) {
55         super(name);
56     }
57
58     /**
59      * Creates new YANG Schema revision source identifier.
60      *
61      * @param name
62      *            Name of schema
63      * @param formattedRevision
64      *            Revision of source in format YYYY-mm-dd
65      */
66     RevisionSourceIdentifier(final String name, final String formattedRevision) {
67         super(Preconditions.checkNotNull(name), Preconditions.checkNotNull(formattedRevision));
68     }
69
70     /**
71      *
72      * Creates new YANG Schema revision source identifier.
73      *
74      * @param name
75      *            Name of schema
76      * @param formattedRevision
77      *            Revision of source in format YYYY-mm-dd. If not present,
78      *            default value will be used.
79      */
80     RevisionSourceIdentifier(final String name, final Optional<String> formattedRevision) {
81         super(name, formattedRevision);
82     }
83
84     /**
85      *
86      * Creates new YANG Schema revision source identifier.
87      *
88      * @param moduleName
89      *            Name of schema
90      * @param revision
91      *            Revision of source in format YYYY-mm-dd. If not present,
92      *            default value will be used.
93      */
94     public static RevisionSourceIdentifier create(final String moduleName,
95             final Optional<String> revision) {
96         return new RevisionSourceIdentifier(moduleName, revision);
97     }
98
99     /**
100      * Creates new YANG Schema revision source identifier.
101      *
102      * @param moduleName
103      *            Name of schema
104      * @param revision
105      *            Revision of source in format YYYY-mm-dd
106      */
107     public static RevisionSourceIdentifier create(final String moduleName, final String revision) {
108         return new RevisionSourceIdentifier(moduleName, revision);
109     }
110
111     /**
112      * Creates new YANG Schema revision source identifier for sources without
113      * a revision.
114      *
115      * @param moduleName
116      *            Name of schema
117      */
118     public static RevisionSourceIdentifier create(final String moduleName) {
119         return new RevisionSourceIdentifier(moduleName);
120     }
121
122     /**
123      * Creates a new RevisionSourceIdentifier based on the provided file name.
124      *
125      * @param fileName file name
126      * @throws IllegalArgumentException when fileName does not have correct format
127      * @throws NullPointerException when fileName is null
128      * @throws ParseException if the revision part has invalid format
129      */
130     public static RevisionSourceIdentifier fromFileName(final String fileName) throws ParseException {
131         final Entry<String, String> split = splitFileName(fileName);
132         if (split.getValue() != null) {
133             SimpleDateFormatUtil.getRevisionFormat().parse(split.getValue());
134         }
135
136         return new RevisionSourceIdentifier(split.getKey(), Optional.fromNullable(split.getValue()));
137     }
138
139     /**
140      * Creates a new RevisionSourceIdentifier based on the provided file name. This variant ignores any revision
141      * part.
142      *
143      * @param fileName file name
144      * @throws IllegalArgumentException when fileName does not have correct format
145      * @throws NullPointerException when fileName is null
146      */
147     public static RevisionSourceIdentifier fromFileNameLenientRevision(final String fileName) {
148         final Entry<String, String> split = splitFileName(fileName);
149         return new RevisionSourceIdentifier(split.getKey(), Optional.fromNullable(split.getValue()));
150     }
151
152     private static Entry<String, String> splitFileName(final String fileName) {
153         Preconditions.checkArgument(fileName.endsWith(RFC6020_YANG_FILE_EXTENSION),
154             "File name '%s' does not end with %s", fileName, RFC6020_YANG_FILE_EXTENSION);
155
156         final String noExt = fileName.substring(0, fileName.length() - RFC6020_YANG_FILE_EXTENSION.length());
157         final int atIndex = noExt.indexOf('@');
158         return atIndex == -1 ? new SimpleImmutableEntry<>(noExt, null)
159                 : new SimpleImmutableEntry<>(noExt.substring(0, atIndex), noExt.substring(atIndex + 1));
160     }
161
162     @Override
163     public int hashCode() {
164         final int prime = 31;
165         int result = 1;
166         result = prime * result + Objects.hashCode(getName());
167         result = prime * result + Objects.hashCode(getRevision());
168         return result;
169     }
170
171     @Override
172     public boolean equals(final Object obj) {
173         if (this == obj) {
174             return true;
175         }
176         if (!(obj instanceof RevisionSourceIdentifier)) {
177             return false;
178         }
179         final RevisionSourceIdentifier other = (RevisionSourceIdentifier) obj;
180         return Objects.equals(getName(), other.getName()) && Objects.equals(getRevision(), other.getRevision());
181     }
182
183     @Override
184     public String toString() {
185         final StringBuilder sb = new StringBuilder("RevisionSourceIdentifier [name=");
186         sb.append(getName());
187
188         final String rev = getRevision();
189         if (rev != null) {
190             sb.append('@').append(rev);
191         }
192         return sb.append(']').toString();
193     }
194 }