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