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