Remove Twitter links.
[SquirrelJME.git] / buildSrc / src / main / java / cc / squirreljme / plugin / swm / SuiteDependency.java
blob0a91ff37dcb5ae8c3eeded0b83154e7f1d991547
1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc.squirreljme.plugin.swm;
12 import cc.squirreljme.plugin.util.NaturalComparator;
13 import cc.squirreljme.plugin.util.StringUtils;
14 import java.lang.ref.Reference;
15 import java.lang.ref.WeakReference;
16 import java.util.Objects;
18 /**
19 * This represents a dependency that a LIBlet or MIDlet may depend on.
21 * @since 2017/02/22
23 public final class SuiteDependency
24 implements Comparable<SuiteDependency>, MarkedDependency
26 /** The dependency type. */
27 protected final SuiteDependencyType type;
29 /** The dependency level. */
30 protected final SuiteDependencyLevel level;
32 /** The name. */
33 protected final SuiteName name;
35 /** The vendor. */
36 protected final SuiteVendor vendor;
38 /** The version range. */
39 protected final SuiteVersionRange version;
41 /** String representation. */
42 private Reference<String> _string;
44 /**
45 * Initializes the dependency which is parsed from the given input string.
47 * @param __s The string to parse.
48 * @throws InvalidSuiteException If the string is not valid.
49 * @throws NullPointerException On null arguments.
50 * @since 2017/02/22
52 public SuiteDependency(String __s)
53 throws InvalidSuiteException, NullPointerException
55 // Check
56 if (__s == null)
57 throw new NullPointerException("NARG");
59 // Trim whitespace
60 __s = __s.trim();
62 // Extract all semicolon positions
63 int[] sc = StringUtils.multipleIndexOf(';', __s);
65 /* {@squirreljme.error DG06 Expected four semi-colons in the
66 dependency field. (The input dependency)} */
67 if (sc.length != 4)
68 throw new InvalidSuiteException(String.format(
69 "AR06 %s", __s));
71 // Split fields
72 String intype = __s.substring(0, sc[0]).trim(),
73 inlevel = __s.substring(sc[0] + 1, sc[1]).trim(),
74 inname = __s.substring(sc[1] + 1, sc[2]).trim(),
75 invendor = __s.substring(sc[2] + 1, sc[3]).trim(),
76 inversion = __s.substring(sc[3] + 1).trim();
78 // Required fields
79 SuiteDependencyType type;
80 this.type = (type = SuiteDependencyType.of(intype));
81 this.level = SuiteDependencyLevel.of(inlevel);
83 // Optional fields
84 SuiteName name;
85 SuiteVendor vendor;
86 SuiteVersionRange version;
87 this.name = (name = (inname.isEmpty() ? null :
88 new SuiteName(inname)));
89 this.vendor = (vendor = (invendor.isEmpty() ? null :
90 new SuiteVendor(invendor)));
91 this.version = (version = (inversion.isEmpty() ? null :
92 new SuiteVersionRange(inversion)));
94 // Check
95 SuiteDependency.__check(type, this.level, name, vendor, version);
98 /**
99 * Initializes the depedency with the given type, level, and where the
100 * remainder of the dependencies are parsed from the specified string.
102 * @param __type The type of dependency this is.
103 * @param __level The level of the dependency.
104 * @param __s The string to decode for the remainder of the dependency.
105 * @throws InvalidSuiteException If the input parameters are not valid.
106 * @throws NullPointerException On null arguments.
107 * @since 2017/11/26
109 public SuiteDependency(SuiteDependencyType __type,
110 SuiteDependencyLevel __level, String __s)
111 throws InvalidSuiteException, NullPointerException
113 if (__type == null || __level == null || __s == null)
114 throw new NullPointerException("NARG");
116 // Trim whitespace
117 __s = __s.trim();
119 // Extract all semicolon positions
120 int[] sc = StringUtils.multipleIndexOf(';', __s);
122 /* {@squirreljme.error DG07 Expected two semi-colons in the
123 dependency field. (The input dependency)} */
124 if (sc.length != 2)
125 throw new InvalidSuiteException(String.format(
126 "AR07 %s", __s));
128 // Split fields
129 String inname = __s.substring(0, sc[0]).trim(),
130 invendor = __s.substring(sc[0] + 1, sc[1]).trim(),
131 inversion = __s.substring(sc[1] + 1).trim();
133 // Parse areas fields
134 SuiteName name;
135 SuiteVendor vendor;
136 SuiteVersionRange version;
137 this.name = (name = (inname.isEmpty() ? null :
138 new SuiteName(inname)));
139 this.vendor = (vendor = (invendor.isEmpty() ? null :
140 new SuiteVendor(invendor)));
141 this.version = (version = (inversion.isEmpty() ? null :
142 new SuiteVersionRange(inversion)));
144 SuiteDependency.__check(__type, __level, name, vendor, version);
146 // Set
147 this.type = __type;
148 this.level = __level;
152 * Initializes the dependency using the given parameters.
154 * @param __type The type of dependency this is.
155 * @param __level The level of the dependency.
156 * @param __name The name.
157 * @param __vendor The vendor.
158 * @param __version The version.
159 * @throws InvalidSuiteException If the input parameters are not valid.
160 * @throws NullPointerException If no type and/or name were specified.
161 * @since 2017/11/26
163 public SuiteDependency(SuiteDependencyType __type,
164 SuiteDependencyLevel __level, SuiteName __name,
165 SuiteVendor __vendor, SuiteVersionRange __version)
166 throws InvalidSuiteException, NullPointerException
168 if (__type == null || __level == null)
169 throw new NullPointerException("NARG");
171 SuiteDependency.__check(__type, __level, __name, __vendor, __version);
173 // Set
174 this.type = __type;
175 this.level = __level;
176 this.name = __name;
177 this.vendor = __vendor;
178 this.version = __version;
182 * {@inheritDoc}
183 * @since 2017/11/30
185 @Override
186 public final int compareTo(SuiteDependency __d)
187 throws NullPointerException
189 if (__d == null)
190 throw new NullPointerException("NARG");
192 // Type first
193 int rv = this.type.compareTo(__d.type);
194 if (rv != 0)
195 return rv;
197 // Optionality
198 rv = this.level.compareTo(__d.level);
199 if (rv != 0)
200 return rv;
202 // Name
203 rv = Objects.<SuiteName>compare(this.name, __d.name,
204 NaturalComparator.<SuiteName>instance());
205 if (rv != 0)
206 return rv;
208 // Vendor
209 rv = Objects.<SuiteVendor>compare(this.vendor, __d.vendor,
210 NaturalComparator.<SuiteVendor>instance());
211 if (rv != 0)
212 return rv;
214 // Version
215 return Objects.<SuiteVersionRange>compare(this.version, __d.version,
216 NaturalComparator.<SuiteVersionRange>instance());
220 * {@inheritDoc}
221 * @since 2017/02/22
223 @Override
224 public boolean equals(Object __o)
226 if (this == __o)
227 return true;
229 // Check
230 if (!(__o instanceof SuiteDependency))
231 return false;
233 // Compare
234 SuiteDependency o = (SuiteDependency)__o;
235 return this.type.equals(o.type) &&
236 this.level.equals(o.level) &&
237 Objects.equals(this.name, o.name) &&
238 Objects.equals(this.vendor, o.vendor) &&
239 Objects.equals(this.version, o.version);
243 * {@inheritDoc}
244 * @since 2017/02/22
246 @Override
247 public int hashCode()
249 return this.type.hashCode() ^
250 this.level.hashCode() ^
251 Objects.hashCode(this.name) ^
252 Objects.hashCode(this.vendor) ^
253 Objects.hashCode(this.version);
257 * {@inheritDoc}
258 * @since 2017/11/22
260 @Override
261 public boolean isOptional()
263 return this.level.isOptional();
267 * Is this a required dependency?
269 * @return {@code true} if this is a required dependency.
270 * @since 2017/11/22
272 public boolean isRequired()
274 return this.level.isRequired();
278 * Returns the dependency level.
280 * @return The dependency level.
281 * @since 2017/02/22
283 public SuiteDependencyLevel level()
285 return this.level;
289 * Returns the dependency name.
291 * @return The dependency name, may be {@code null}.
292 * @since 2017/02/22
294 public SuiteName name()
296 return this.name;
300 * {@inheritDoc}
301 * @since 2017/12/31
303 @Override
304 public boolean matchesProvided(MarkedProvided __mp)
305 throws NullPointerException
307 if (__mp == null)
308 throw new NullPointerException("NARG");
310 SuiteDependencyType type = this.type;
311 Class<?> mpclass = __mp.getClass();
312 SuiteName name = this.name;
313 SuiteVendor vendor = this.vendor;
314 SuiteVersionRange version = this.version;
316 // Depends
317 switch (type)
319 // Proprietary match
320 case PROPRIETARY:
321 // Potential internal project name
322 if (__mp instanceof InternalName)
324 String myname = name.toString();
326 // Needs at sign
327 int dxat;
328 if ((dxat = myname.indexOf('@')) < 0)
329 return false;
331 // Prefix must be project reference
332 if (!myname.substring(0, dxat).
333 equals("squirreljme.project"))
334 return false;
336 // Otherwise the project name must match
337 return myname.substring(dxat + 1).
338 equals(((InternalName)__mp).name());
341 // No matches
342 return false;
344 // Library
345 case LIBLET:
346 // Typed suite information
347 if (__mp instanceof TypedSuite)
349 TypedSuite other = (TypedSuite)__mp;
350 SuiteIdentifier ident = other.suite();
352 // Only match other libraries
353 if (other.type() != JavaMEMidletType.LIBRARY)
354 return false;
356 // Must match name
357 if (!name.equals(ident.name()))
358 return false;
360 // Match vendor if specified
361 if (vendor != null)
362 if (!vendor.equals(ident.vendor()))
363 return false;
365 // Check if version in range if specified
366 if (version != null)
367 if (!version.inRange(ident.version()))
368 return false;
370 // Is okay!
371 return true;
374 // Unknown
375 else
376 return false;
378 // Standard
379 case STANDARD:
380 if (__mp instanceof JavaMEStandard)
382 JavaMEStandard other = (JavaMEStandard)__mp;
384 // Must match name
385 if (!name.equals(other.name()))
386 return false;
388 // Match vendor if specified
389 if (vendor != null)
390 if (!vendor.equals(other.vendor()))
391 return false;
393 // Check if version in range if specified
394 if (version != null)
395 if (!version.inRange(other.version()))
396 return false;
398 // Matches!
399 return true;
402 // Not a standard
403 else
404 return false;
406 /* {@squirreljme.error DG08 Illegal dependency check.
407 (The dependency type; The target class)} */
408 default:
409 throw new RuntimeException(String.format("AR08 %s %s",
410 type, mpclass));
415 * Returns a dependency which is the same as this one except that it is
416 * required.
418 * @return This dependency but required.
419 * @since 2017/11/26
421 public SuiteDependency toRequired()
423 if (this.isRequired())
424 return this;
425 return new SuiteDependency(this.type, SuiteDependencyLevel.REQUIRED,
426 this.name, this.vendor, this.version);
430 * Returns a dependency which is the same as this one except that it is
431 * optional.
433 * @return This dependency but optional.
434 * @since 2017/11/26
436 public SuiteDependency toOptional()
438 if (this.isOptional())
439 return this;
440 return new SuiteDependency(this.type, SuiteDependencyLevel.OPTIONAL,
441 this.name, this.vendor, this.version);
445 * {@inheritDoc}
446 * @since 2017/02/22
448 @Override
449 public String toString()
451 // Get
452 Reference<String> ref = this._string;
453 String rv;
455 // Cache?
456 if (ref == null || null == (rv = ref.get()))
458 // These are optional
459 SuiteName name = this.name;
460 SuiteVendor vendor = this.vendor;
461 SuiteVersionRange version = this.version;
463 // Generate
464 this._string = new WeakReference<>((rv = String.format(
465 "%s;%s;%s;%s;%s", this.type, this.level,
466 (name == null ? "" : name),
467 (vendor == null ? "" : vendor),
468 (version == null ? "" : version))));
471 // Return it
472 return rv;
476 * Returns the dependency type.
478 * @return The dependency type.
479 * @since 2017/02/22
481 public SuiteDependencyType type()
483 return this.type;
487 * Returns the dependency vendor.
489 * @return The dependency vendor, may be {@code null}.
490 * @since 2017/02/22
492 public SuiteVendor vendor()
494 return this.vendor;
498 * Returns the dependency version.
500 * @return The dependency version, may be {@code null}.
501 * @since 2017/02/22
503 public SuiteVersionRange version()
505 return this.version;
509 * Checks whether the provided parameters are correct.
511 * @param __type The type of dependency this is.
512 * @param __level The level of the dependency.
513 * @param __name The name.
514 * @param __vendor The vendor.
515 * @param __version The version.
516 * @throws InvalidSuiteException If the input parameters are not valid.
517 * @since 2017/11/26
519 private static void __check(SuiteDependencyType __type,
520 SuiteDependencyLevel __level, SuiteName __name,
521 SuiteVendor __vendor, SuiteVersionRange __version)
522 throws InvalidSuiteException
524 /* {@squirreljme.error DG09 Dependencies on LIBlets must have the
525 name, vendor, and version set. (The type; The level; The name;
526 The vendor; The version)} */
527 if (__type == SuiteDependencyType.LIBLET && (__name == null ||
528 __vendor == null || __version == null))
529 throw new InvalidSuiteException(
530 String.format("AR09 %s %s %s %s %s", __type, __level, __name,
531 __vendor, __version));