| 1 | /******************************************************************************* | 
| 2 |  * Copyright (c) 2007, 2009 IBM Corporation and others. | 
| 3 |  * All rights reserved. This program and the accompanying materials | 
| 4 |  * are made available under the terms of the Eclipse Public License v1.0 | 
| 5 |  * which accompanies this distribution, and is available at | 
| 6 |  * http://www.eclipse.org/legal/epl-v10.html | 
| 7 |  * | 
| 8 |  * Contributors: | 
| 9 |  *     IBM Corporation - initial API and implementation | 
| 10 |  *******************************************************************************/ | 
| 11 | package org.eclipse.pde.api.tools.internal.comparator; | 
| 12 |   | 
| 13 | import java.io.PrintWriter; | 
| 14 | import java.io.StringWriter; | 
| 15 |   | 
| 16 | import org.eclipse.pde.api.tools.internal.problems.ApiProblemFactory; | 
| 17 | import org.eclipse.pde.api.tools.internal.provisional.RestrictionModifiers; | 
| 18 | import org.eclipse.pde.api.tools.internal.provisional.comparator.DeltaProcessor; | 
| 19 | import org.eclipse.pde.api.tools.internal.provisional.comparator.DeltaVisitor; | 
| 20 | import org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta; | 
| 21 | import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem; | 
| 22 | import org.eclipse.pde.api.tools.internal.util.Util; | 
| 23 |   | 
| 24 | // TODO add javadoc | 
| 25 | public class Delta implements IDelta { | 
| 26 |         private static final IDelta[] EMPTY_CHILDREN = new IDelta[0]; | 
| 27 |         private static final int INITIAL_SIZE = 4; | 
| 28 |         public static final int MODIFIERS_MASK = 0xFFFF; | 
| 29 |         public static final int NEW_MODIFIERS_OFFSET = 16; | 
| 30 |   | 
| 31 |         /** | 
| 32 |          * Writes the delta to the given {@link PrintWriter} | 
| 33 |          * @param delta | 
| 34 |          * @param writer | 
| 35 |          */ | 
| 36 |         private static void print(IDelta delta, PrintWriter writer) { | 
| 37 |                 writer.print("delta (elementType: "); //$NON-NLS-1$ | 
| 38 |                 switch(delta.getElementType()) { | 
| 39 |                         case IDelta.FIELD_ELEMENT_TYPE : | 
| 40 |                                 writer.print("field"); //$NON-NLS-1$ | 
| 41 |                                 break; | 
| 42 |                         case IDelta.ANNOTATION_ELEMENT_TYPE : | 
| 43 |                                 writer.print("annotation type"); //$NON-NLS-1$ | 
| 44 |                                 break; | 
| 45 |                         case IDelta.CLASS_ELEMENT_TYPE : | 
| 46 |                                 writer.print("class type"); //$NON-NLS-1$ | 
| 47 |                                 break; | 
| 48 |                         case IDelta.INTERFACE_ELEMENT_TYPE : | 
| 49 |                                 writer.print("interface type"); //$NON-NLS-1$ | 
| 50 |                                 break; | 
| 51 |                         case IDelta.ENUM_ELEMENT_TYPE : | 
| 52 |                                 writer.print("enum type"); //$NON-NLS-1$ | 
| 53 |                                 break; | 
| 54 |                         case IDelta.API_COMPONENT_ELEMENT_TYPE : | 
| 55 |                                 writer.print("API component type"); //$NON-NLS-1$ | 
| 56 |                                 break; | 
| 57 |                         case IDelta.METHOD_ELEMENT_TYPE : | 
| 58 |                                 writer.print("method"); //$NON-NLS-1$ | 
| 59 |                                 break; | 
| 60 |                         case IDelta.CONSTRUCTOR_ELEMENT_TYPE : | 
| 61 |                                 writer.print("constructor"); //$NON-NLS-1$ | 
| 62 |                                 break; | 
| 63 |                         case IDelta.API_PROFILE_ELEMENT_TYPE : | 
| 64 |                                 writer.print("API profile"); //$NON-NLS-1$ | 
| 65 |                                 break; | 
| 66 |                 } | 
| 67 |                 writer.print(", kind : "); //$NON-NLS-1$ | 
| 68 |                 writer.print(delta.getKind()); | 
| 69 |                 writer.print(", flags : "); //$NON-NLS-1$ | 
| 70 |                 writer.print(delta.getFlags()); | 
| 71 |                 writer.print(')'); | 
| 72 |                 writer.print('-'); | 
| 73 |                 writer.print(Util.getDetail(delta)); | 
| 74 |         } | 
| 75 |         private IDelta[] children; | 
| 76 |         private String componentID; | 
| 77 |         private String[] datas; | 
| 78 |         private int deltasCounter; | 
| 79 |         private int elementType; | 
| 80 |         private int flags; | 
| 81 |         private String key; | 
| 82 |   | 
| 83 |         private int kind; | 
| 84 |         private int modifiers; | 
| 85 |         private int restrictions; | 
| 86 |   | 
| 87 |         private String typeName; | 
| 88 |   | 
| 89 |         /** | 
| 90 |          * Constructor | 
| 91 |          */ | 
| 92 |         public Delta() { | 
| 93 |                 // use for root delta | 
| 94 |         } | 
| 95 |   | 
| 96 |         /** | 
| 97 |          * Constructor | 
| 98 |          * @param elementType | 
| 99 |          * @param kind | 
| 100 |          * @param flags | 
| 101 |          * @param restrictions | 
| 102 |          * @param modifiers | 
| 103 |          * @param classFile | 
| 104 |          * @param key | 
| 105 |          * @param data | 
| 106 |          */ | 
| 107 |         public Delta(String componentID, int elementType, int kind, int flags, int restrictions, int oldModifiers, int newModifiers, String typeName, String key, String data) { | 
| 108 |                 this(componentID, elementType, kind, flags, restrictions, oldModifiers, newModifiers, typeName, key, new String[] {data}); | 
| 109 |         } | 
| 110 |   | 
| 111 |         public Delta(String componentID, int elementType, int kind, int flags, int restrictions, int oldModifiers, int newModifiers, String typeName, String key, String[] datas) { | 
| 112 |                 this.componentID = componentID; | 
| 113 |                 this.elementType = elementType; | 
| 114 |                 this.kind = kind; | 
| 115 |                 this.flags = flags; | 
| 116 |                 this.modifiers = (newModifiers & MODIFIERS_MASK) << 16 | (oldModifiers & MODIFIERS_MASK); | 
| 117 |                 this.typeName = typeName == null ? Util.EMPTY_STRING : typeName; | 
| 118 |                 this.restrictions = restrictions; | 
| 119 |                 this.key = key; | 
| 120 |                 this.datas = datas; | 
| 121 |         } | 
| 122 |          | 
| 123 |         /** | 
| 124 |          * Constructor | 
| 125 |          * @param elementType | 
| 126 |          * @param kind | 
| 127 |          * @param flags | 
| 128 |          * @param classFile | 
| 129 |          * @param key | 
| 130 |          * @param data | 
| 131 |          */ | 
| 132 |         public Delta(String componentID, int elementType, int kind, int flags, String typeName, String key, String data) { | 
| 133 |                 this(componentID, elementType, kind, flags, RestrictionModifiers.NO_RESTRICTIONS, 0, 0, typeName, key, data); | 
| 134 |         } | 
| 135 |   | 
| 136 |         /* (non-Javadoc) | 
| 137 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#accept(org.eclipse.pde.api.tools.internal.provisional.comparator.DeltaVisitor) | 
| 138 |          */ | 
| 139 |         public void accept(DeltaVisitor visitor) { | 
| 140 |                 if (visitor.visit(this)) { | 
| 141 |                         if (this.children != null) { | 
| 142 |                                 for (int i = 0, max = this.deltasCounter; i < max; i++) { | 
| 143 |                                         IDelta delta = this.children[i]; | 
| 144 |                                         delta.accept(visitor); | 
| 145 |                                 } | 
| 146 |                         } | 
| 147 |                 } | 
| 148 |                 visitor.endVisit(this); | 
| 149 |         } | 
| 150 |   | 
| 151 |         /** | 
| 152 |          * Adds a child delta to this delta. If the specified delta  | 
| 153 |          * is <code>null</code> no work is done. | 
| 154 |          * @param delta the new child delta | 
| 155 |          */ | 
| 156 |         public void add(IDelta delta) { | 
| 157 |                 if (delta == null) { | 
| 158 |                         return; | 
| 159 |                 } | 
| 160 |                 if (this.children == null) { | 
| 161 |                         this.children = new Delta[INITIAL_SIZE]; | 
| 162 |                         this.deltasCounter = 0; | 
| 163 |                 } | 
| 164 |                 int length = this.children.length; | 
| 165 |                 if (this.deltasCounter == length) { | 
| 166 |                         System.arraycopy(this.children, 0, (this.children = new IDelta[length * 2]), 0, length); | 
| 167 |                 } | 
| 168 |                 this.children[this.deltasCounter++] = delta; | 
| 169 |         } | 
| 170 |   | 
| 171 |         /* (non-Javadoc) | 
| 172 |          * @see java.lang.Object#equals(java.lang.Object) | 
| 173 |          */ | 
| 174 |         public boolean equals(Object obj) { | 
| 175 |                 if (this == obj) | 
| 176 |                         return true; | 
| 177 |                 if (obj == null) | 
| 178 |                         return false; | 
| 179 |                 if (!(obj instanceof Delta)) | 
| 180 |                         return false; | 
| 181 |                 Delta other = (Delta) obj; | 
| 182 |                 if (this.elementType != other.elementType) | 
| 183 |                         return false; | 
| 184 |                 if (this.flags != other.flags) | 
| 185 |                         return false; | 
| 186 |                 if (this.kind != other.kind) | 
| 187 |                         return false; | 
| 188 |                 if (this.modifiers != other.modifiers) | 
| 189 |                         return false; | 
| 190 |                 if (this.restrictions != other.restrictions) | 
| 191 |                         return false; | 
| 192 |                 if (this.typeName == null) { | 
| 193 |                         if (other.typeName != null) | 
| 194 |                                 return false; | 
| 195 |                 } else if (!this.typeName.equals(other.typeName)) | 
| 196 |                         return false; | 
| 197 |                 if (this.key == null) { | 
| 198 |                         if (other.key != null) | 
| 199 |                                 return false; | 
| 200 |                 } else if (!this.key.equals(other.key)) | 
| 201 |                         return false; | 
| 202 |                 if (this.datas == null) { | 
| 203 |                         if (other.datas != null) | 
| 204 |                                 return false; | 
| 205 |                 } else if (other.datas == null) { | 
| 206 |                         return false; | 
| 207 |                 } else { | 
| 208 |                         if (this.datas.length != other.datas.length) { | 
| 209 |                                 return false; | 
| 210 |                         } | 
| 211 |                         for (int i = 0, max = this.datas.length; i < max; i++) { | 
| 212 |                                 if (!this.datas[i].equals(other.datas[i])) { | 
| 213 |                                         return false; | 
| 214 |                                 } | 
| 215 |                         } | 
| 216 |                 } | 
| 217 |                 if (this.componentID == null) { | 
| 218 |                         if (other.componentID != null) | 
| 219 |                                 return false; | 
| 220 |                 } else if (!this.componentID.equals(other.componentID)) | 
| 221 |                         return false; | 
| 222 |                 return true; | 
| 223 |         } | 
| 224 |          | 
| 225 |         public String getComponentVersionId() { | 
| 226 |                 return this.componentID; | 
| 227 |         } | 
| 228 |   | 
| 229 |         /* (non-Javadoc) | 
| 230 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#getArguments() | 
| 231 |          */ | 
| 232 |         public String[] getArguments() { | 
| 233 |                 if(this.datas == null) { | 
| 234 |                         return new String[] { typeName }; | 
| 235 |                 } | 
| 236 |                 return this.datas; | 
| 237 |         } | 
| 238 |          | 
| 239 |         /* (non-Javadoc) | 
| 240 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#getChildren() | 
| 241 |          */ | 
| 242 |         public IDelta[] getChildren() { | 
| 243 |                 if (this.children == null) return EMPTY_CHILDREN; | 
| 244 |                 int resizeLength = this.deltasCounter; | 
| 245 |                 if (resizeLength != this.children.length) { | 
| 246 |                         System.arraycopy(this.children, 0, (this.children = new IDelta[resizeLength]), 0, resizeLength); | 
| 247 |                 } | 
| 248 |                 return this.children; | 
| 249 |         } | 
| 250 |   | 
| 251 |         /* (non-Javadoc) | 
| 252 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#getElementType() | 
| 253 |          */ | 
| 254 |         public int getElementType() { | 
| 255 |                 return this.elementType; | 
| 256 |         } | 
| 257 |   | 
| 258 |         /* (non-Javadoc) | 
| 259 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#getFlags() | 
| 260 |          */ | 
| 261 |         public int getFlags() { | 
| 262 |                 return this.flags; | 
| 263 |         } | 
| 264 |          | 
| 265 |         /* (non-Javadoc) | 
| 266 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#getKey() | 
| 267 |          */ | 
| 268 |         public String getKey() { | 
| 269 |                 return this.key; | 
| 270 |         } | 
| 271 |          | 
| 272 |         /* (non-Javadoc) | 
| 273 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#getKind() | 
| 274 |          */ | 
| 275 |         public int getKind() { | 
| 276 |                 return this.kind; | 
| 277 |         } | 
| 278 |          | 
| 279 |         /* (non-Javadoc) | 
| 280 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#getMessage() | 
| 281 |          */ | 
| 282 |         public String getMessage() { | 
| 283 |                 if (DeltaProcessor.isCompatible(this)) { | 
| 284 |                         return Messages.getCompatibleLocalizedMessage(this); | 
| 285 |                 } | 
| 286 |                 int id = ApiProblemFactory.getProblemMessageId(IApiProblem.CATEGORY_COMPATIBILITY,  | 
| 287 |                                 this.elementType, this.kind, this.flags); | 
| 288 |                 return ApiProblemFactory.getLocalizedMessage(id, (this.datas != null ? this.datas : null)); | 
| 289 |         } | 
| 290 |   | 
| 291 |         /* (non-Javadoc) | 
| 292 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#getModifiers() | 
| 293 |          */ | 
| 294 |         public int getNewModifiers() { | 
| 295 |                 return (this.modifiers >>> NEW_MODIFIERS_OFFSET); | 
| 296 |         } | 
| 297 |         public int getOldModifiers() { | 
| 298 |                 return this.modifiers & MODIFIERS_MASK; | 
| 299 |         } | 
| 300 |         /* (non-Javadoc) | 
| 301 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#getRestrictions() | 
| 302 |          */ | 
| 303 |         public int getRestrictions() { | 
| 304 |                 return this.restrictions; | 
| 305 |         } | 
| 306 |          | 
| 307 |         /* (non-Javadoc) | 
| 308 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#getTypeName() | 
| 309 |          */ | 
| 310 |         public String getTypeName() { | 
| 311 |                 return this.typeName; | 
| 312 |         } | 
| 313 |   | 
| 314 |         /* (non-Javadoc) | 
| 315 |          * @see java.lang.Object#hashCode() | 
| 316 |          */ | 
| 317 |         public int hashCode() { | 
| 318 |                 final int prime = 31; | 
| 319 |                 int result = 1; | 
| 320 |                 result = prime * result + ((this.datas == null) ? 0 : this.datas.hashCode()); | 
| 321 |                 result = prime * result + this.elementType; | 
| 322 |                 result = prime * result + this.flags; | 
| 323 |                 result = prime * result + ((this.key == null) ? 0 : this.key.hashCode()); | 
| 324 |                 result = prime * result + ((this.typeName == null) ? 0 : this.typeName.hashCode()); | 
| 325 |                 result = prime * result + this.kind; | 
| 326 |                 result = prime * result + this.modifiers; | 
| 327 |                 result = prime * result + this.restrictions; | 
| 328 |                 result = prime * result + ((this.componentID == null) ? 0 : this.componentID.hashCode()); | 
| 329 |                 return result; | 
| 330 |         } | 
| 331 |   | 
| 332 |         /* (non-Javadoc) | 
| 333 |          * @see org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta#isEmpty() | 
| 334 |          */ | 
| 335 |         public boolean isEmpty() { | 
| 336 |                 return this.deltasCounter == 0; | 
| 337 |         } | 
| 338 |          | 
| 339 |         /* (non-Javadoc) | 
| 340 |          * @see java.lang.Object#toString() | 
| 341 |          */ | 
| 342 |         public String toString() { | 
| 343 |                 StringWriter writer = new StringWriter(); | 
| 344 |                 PrintWriter printWriter = new PrintWriter(writer); | 
| 345 |                 if (this.children == null) { | 
| 346 |                         print(this, printWriter); | 
| 347 |                 } else { | 
| 348 |                         printWriter.print('['); | 
| 349 |                         for (int i = 0, max = this.deltasCounter; i < max; i++) { | 
| 350 |                                 if (i > 0) { | 
| 351 |                                         printWriter.println(','); | 
| 352 |                                 } | 
| 353 |                                 printWriter.print(this.children[i]); | 
| 354 |                         } | 
| 355 |                         printWriter.print(']'); | 
| 356 |                 } | 
| 357 |                 return String.valueOf(writer.getBuffer()); | 
| 358 |         } | 
| 359 | } |