1 package com.atlassian.plugin.descriptors;
2
3 import com.atlassian.plugin.ModuleDescriptor;
4
5 import javax.annotation.concurrent.NotThreadSafe;
6
7 import static com.google.common.base.Preconditions.checkNotNull;
8
9 /**
10 * @since v2.8
11 */
12 public final class ModuleDescriptors {
13 /**
14 * Assists in implementing a consistent implementation of {@link ModuleDescriptor#equals(Object)} methods for
15 * module descriptors based on the complete key of the descriptor.
16 * <p>
17 * The full specification of the <tt>equals(Object obj)</tt> contract is defined by
18 * {@link ModuleDescriptor#equals(Object)}
19 * <p>
20 * Usage:
21 * <ol>
22 * <li>If you are using this builder to implement the <tt>equals(Object obj)</tt> method in a module descriptor
23 * implementation:
24 * <p>
25 * <code>
26 * new ModuleDescriptors.EqualsBuilder().descriptor(this).isEqualTo(obj);
27 * </code>
28 * </li>
29 * <li>If you are using this builder to compare descriptors from outside a module descriptor implementation;
30 * given two descriptor instances, <tt>descriptor1</tt> and <tt>descriptor2</tt>:
31 * <p>
32 * <code>
33 * new ModuleDescriptors.EqualsBuilder().descriptor(descriptor1).isEqualTo(descriptor2);
34 * </code>
35 * </li>
36 * </ol>
37 *
38 * @since 2.8.0
39 */
40 @NotThreadSafe
41 public static class EqualsBuilder {
42 private ModuleDescriptor descriptor;
43
44 /**
45 * Sets the module descriptor to create an <code>equals</code> implementation for.
46 *
47 * @param descriptor the module descriptor.
48 * @return this builder instance.
49 */
50 public EqualsBuilder descriptor(final ModuleDescriptor descriptor) {
51 checkNotNull(descriptor, "Tried to build an equals implementation for a null module descriptor. " +
52 "This is not allowed.");
53 this.descriptor = descriptor;
54 return this;
55 }
56
57 /**
58 * Returns <tt>true</tt> if the given object is also a module descriptor and the two descriptors have the same
59 * "complete key" as determined by {@link com.atlassian.plugin.ModuleDescriptor#getCompleteKey()}.
60 *
61 * @param obj object to be compared for equality with this module descriptor.
62 * @return <tt>true</tt> if the specified object is equal to this module descriptor.
63 */
64 public boolean isEqualTo(final Object obj) {
65 checkNotNull(descriptor, "Tried to build an equals implementation for a null module descriptor. " +
66 "This is not allowed.");
67
68 if (descriptor == obj) {
69 return true;
70 }
71
72 if (!(obj instanceof ModuleDescriptor)) {
73 return false;
74 }
75
76 ModuleDescriptor rhs = (ModuleDescriptor) obj;
77
78 return new org.apache.commons.lang3.builder.EqualsBuilder().
79 append(descriptor.getCompleteKey(), rhs.getCompleteKey()).
80 isEquals();
81 }
82 }
83
84 /**
85 * Assists in implementing {@link Object#hashCode()} methods for module descriptors based on the <code>hashCode</code>
86 * of their complete key.
87 * <p>
88 * The full specification of the <tt>hashCode()</tt> contract is defined by
89 * {@link ModuleDescriptor#hashCode()}
90 * <p>
91 * Usage:
92 * <ol>
93 * <li>If you are using this builder to implement the <tt>hashCode()</tt> method in a module descriptor
94 * implementation:
95 * <p>
96 * <code>
97 * new ModuleDescriptors.HashCodeBuilder().descriptor(this).toHashCode();
98 * </code>
99 * </li>
100 * <li>If you are using this builder to calculate the hashCode of a descriptor from outside a module descriptor
101 * implementation; given a descriptor instance <tt>desc</tt>:
102 * <p>
103 * <code>
104 * new ModuleDescriptors.EqualsBuilder().descriptor(desc).toHashCode();
105 * </code>
106 * </li>
107 * </ol>
108 *
109 * @since 2.8.0
110 */
111 @NotThreadSafe
112 public static class HashCodeBuilder {
113 private ModuleDescriptor descriptor;
114
115 /**
116 * Sets the module descriptor to create a <code>hashCode</code> implementation for.
117 *
118 * @param descriptor the descriptor. Must not be null.
119 * @return this builder.
120 */
121 public HashCodeBuilder descriptor(final ModuleDescriptor descriptor) {
122 checkNotNull(descriptor, "Tried to calculate the hash code of a null module descriptor.");
123 this.descriptor = descriptor;
124 return this;
125 }
126
127 /**
128 * Return the computed <code>hashCode</code> for this module descriptor.
129 *
130 * @return <code>hashCode</code> based on the hashCode of the complete key of the module descriptor.
131 */
132 public int toHashCode() {
133 checkNotNull(descriptor, "Tried to calculate the hash code of a null module descriptor.");
134 return descriptor.getCompleteKey() == null ? 0 : descriptor.getCompleteKey().hashCode();
135 }
136
137 /**
138 * The computed <code>hashCode</code> from toHashCode() is returned due to the likelihood
139 * of bugs in mis-calling toHashCode() and the unlikeliness of it mattering what the hashCode for
140 * HashCodeBuilder itself is.
141 *
142 * @return <code>hashCode</code> based on the complete key of the module descriptor.
143 */
144 public int hashCode() {
145 return toHashCode();
146 }
147 }
148 }