View Javadoc
1   /*
2    * Themis: Java Project Framework
3    * Copyright 2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  
18  package io.github.tonywasher.joceanus.themis.parser.maven;
19  
20  import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
21  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
22  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
23  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
24  import io.github.tonywasher.joceanus.themis.parser.base.ThemisChar;
25  import io.github.tonywasher.joceanus.themis.parser.base.ThemisDataResource;
26  import org.w3c.dom.Element;
27  
28  import java.util.Objects;
29  
30  /**
31   * Maven Module Id.
32   */
33  public final class ThemisMavenId
34          implements MetisFieldItem {
35      /**
36       * ElementParser.
37       */
38      interface ThemisXElementParser {
39          /**
40           * Obtain element value.
41           *
42           * @param pElement the element
43           * @param pValue   the value name
44           * @return the value
45           * @throws OceanusException on error
46           */
47          String getElementValue(Element pElement,
48                                 String pValue) throws OceanusException;
49      }
50  
51      /**
52       * Report fields.
53       */
54      private static final MetisFieldSet<ThemisMavenId> FIELD_DEFS = MetisFieldSet.newFieldSet(ThemisMavenId.class);
55  
56      /*
57       * Declare Fields.
58       */
59      static {
60          FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_GROUPID, ThemisMavenId::getGroupId);
61          FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_ARTIFACTID, ThemisMavenId::getArtifactId);
62          FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_VERSION, ThemisMavenId::getVersion);
63          FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_CLASSIFIER, ThemisMavenId::getClassifier);
64          FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_SCOPE, ThemisMavenId::getScope);
65          FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_OPTIONAL, ThemisMavenId::isOptional);
66      }
67  
68      /**
69       * GroupId element.
70       */
71      private static final String EL_GROUPID = "groupId";
72  
73      /**
74       * ArtifactId element.
75       */
76      private static final String EL_ARTIFACTID = "artifactId";
77  
78      /**
79       * Version element.
80       */
81      private static final String EL_VERSION = "version";
82  
83      /**
84       * Scope element.
85       */
86      private static final String EL_SCOPE = "scope";
87  
88      /**
89       * Classifier element.
90       */
91      private static final String EL_CLASSIFIER = "classifier";
92  
93      /**
94       * Optional element.
95       */
96      private static final String EL_OPTIONAL = "optional";
97  
98      /**
99       * The artifactId.
100      */
101     private final String theArtifactId;
102 
103     /**
104      * The scope.
105      */
106     private final String theScope;
107 
108     /**
109      * The classifier.
110      */
111     private final String theClassifier;
112 
113     /**
114      * Optional.
115      */
116     private final String isOptional;
117 
118     /**
119      * The groupId.
120      */
121     private String theGroupId;
122 
123     /**
124      * The version.
125      */
126     private String theVersion;
127 
128     /**
129      * Constructor.
130      *
131      * @param pParser  the parser
132      * @param pElement the element containing the values
133      * @throws OceanusException on error
134      */
135     ThemisMavenId(final ThemisXElementParser pParser,
136                   final Element pElement) throws OceanusException {
137         /* Access the values */
138         theGroupId = pParser.getElementValue(pElement, EL_GROUPID);
139         theArtifactId = pParser.getElementValue(pElement, EL_ARTIFACTID);
140         theVersion = pParser.getElementValue(pElement, EL_VERSION);
141         theScope = pParser.getElementValue(pElement, EL_SCOPE);
142         theClassifier = pParser.getElementValue(pElement, EL_CLASSIFIER);
143         isOptional = pParser.getElementValue(pElement, EL_OPTIONAL);
144     }
145 
146     /**
147      * Constructor.
148      *
149      * @param pParser  the parser
150      * @param pElement the element containing the values
151      * @param pParent  the parentId
152      * @throws OceanusException on error
153      */
154     ThemisMavenId(final ThemisXElementParser pParser,
155                   final Element pElement,
156                   final ThemisMavenId pParent) throws OceanusException {
157         /* Process as much as we can */
158         this(pParser, pElement);
159 
160         /* Handle missing groupId/version */
161         if (theGroupId == null && pParent != null) {
162             theGroupId = pParent.getGroupId();
163         }
164         if (theVersion == null && pParent != null) {
165             theVersion = pParent.getVersion();
166         }
167 
168         /* If we have a ranged version, set to null */
169         if (theVersion != null
170                 && theVersion.startsWith(String.valueOf(ThemisChar.ARRAY_OPEN))) {
171             theVersion = null;
172         }
173     }
174 
175     /**
176      * Constructor.
177      *
178      * @param pSource  the source Id
179      * @param pVersion the new version
180      */
181     ThemisMavenId(final ThemisMavenId pSource,
182                   final String pVersion) {
183         /* Access the values */
184         theGroupId = pSource.getGroupId();
185         theArtifactId = pSource.getArtifactId();
186         theVersion = pVersion;
187         theScope = pSource.getScope();
188         theClassifier = pSource.getClassifier();
189         isOptional = pSource.isOptional();
190     }
191 
192     @Override
193     public MetisFieldSet<ThemisMavenId> getDataFieldSet() {
194         return FIELD_DEFS;
195     }
196 
197     @Override
198     public String formatObject(final OceanusDataFormatter pFormatter) {
199         return toString();
200     }
201 
202     /**
203      * Obtain the groupId.
204      *
205      * @return the groupId
206      */
207     public String getGroupId() {
208         return theGroupId;
209     }
210 
211     /**
212      * Obtain the artifactId.
213      *
214      * @return the artifactId
215      */
216     public String getArtifactId() {
217         return theArtifactId;
218     }
219 
220     /**
221      * Obtain the version.
222      *
223      * @return the version
224      */
225     public String getVersion() {
226         return theVersion;
227     }
228 
229     /**
230      * Obtain the scope.
231      *
232      * @return the scope
233      */
234     public String getScope() {
235         return theScope;
236     }
237 
238     /**
239      * Obtain the classifier.
240      *
241      * @return the classifier
242      */
243     public String getClassifier() {
244         return theClassifier;
245     }
246 
247     /**
248      * Obtain the optional.
249      *
250      * @return the optional
251      */
252     public String isOptional() {
253         return isOptional;
254     }
255 
256     /**
257      * is the dependency skippable?
258      *
259      * @return true/false
260      */
261     public boolean isSkippable() {
262         return "test".equals(theScope)
263                 || "runtime".equals(theScope)
264                 || "provided".equals(theScope)
265                 || isOptional != null;
266     }
267 
268     /**
269      * Adjust the version.
270      *
271      * @param pVersion the new version.
272      */
273     void adjustVersion(final String pVersion) {
274         theVersion = pVersion;
275     }
276 
277     @Override
278     public boolean equals(final Object pThat) {
279         /* Handle the trivial cases */
280         if (this == pThat) {
281             return true;
282         }
283         if (pThat == null) {
284             return false;
285         }
286 
287         /* Make sure that the object is a MavenId */
288         if (!(pThat instanceof ThemisMavenId myThat)) {
289             return false;
290         }
291 
292         /* Check components */
293         return Objects.equals(theGroupId, myThat.getGroupId())
294                 && Objects.equals(theArtifactId, myThat.getArtifactId())
295                 && Objects.equals(theVersion, myThat.getVersion())
296                 && Objects.equals(theClassifier, myThat.getClassifier());
297     }
298 
299     /**
300      * Does the id match (excluding version)?
301      *
302      * @param pThat the target id
303      * @return true/false
304      */
305     public boolean equalsPrefix(final Object pThat) {
306         /* Handle the trivial cases */
307         if (this == pThat) {
308             return true;
309         }
310         if (pThat == null) {
311             return false;
312         }
313 
314         /* Make sure that the object is a MavenId */
315         if (!(pThat instanceof ThemisMavenId myThat)) {
316             return false;
317         }
318 
319         /* Check components */
320         return Objects.equals(theGroupId, myThat.getGroupId())
321                 && Objects.equals(theArtifactId, myThat.getArtifactId())
322                 && Objects.equals(theClassifier, myThat.getClassifier());
323     }
324 
325     @Override
326     public int hashCode() {
327         return Objects.hash(theGroupId, theArtifactId, theVersion, theClassifier);
328     }
329 
330     @Override
331     public String toString() {
332         final String myName = theGroupId + ThemisChar.COLON + theArtifactId + ThemisChar.COLON + theVersion;
333         return theClassifier == null ? myName : myName + ThemisChar.COLON + theClassifier;
334     }
335 }