View Javadoc
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           * &quot;complete key&quot; 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 }