diff options
Diffstat (limited to 'FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/JavaClassVersionCompare.java')
-rwxr-xr-x | FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/JavaClassVersionCompare.java | 654 |
1 files changed, 654 insertions, 0 deletions
diff --git a/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/JavaClassVersionCompare.java b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/JavaClassVersionCompare.java new file mode 100755 index 000000000..26a7fd9ff --- /dev/null +++ b/FROMCVS/org.eclipse.pde.tools.versioning/src/org/eclipse/pde/tools/internal/versioning/JavaClassVersionCompare.java @@ -0,0 +1,654 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.pde.tools.internal.versioning; + +import java.io.InputStream; +import java.util.*; +import org.eclipse.core.runtime.*; +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.util.*; +import org.eclipse.osgi.util.NLS; +import org.eclipse.pde.tools.versioning.IVersionCompare; + +/** + * ClassSourceVersionCompare + */ +public class JavaClassVersionCompare implements VersionCompareConstants { + // MultiStatus instance used to store IStatus objects which indicate changes between two java classes + private MultiStatus finalResult; + // + private boolean hasMajorChange; + private boolean hasMinorChange; + private boolean hasMicroChange; + private boolean hasError; + + /** + * Constructor + */ + public JavaClassVersionCompare() { + super(); + } + + /* (non-Javadoc) + * @see org.eclipse.pde.tools.internal.versioning.VersionCompareDispatcher#checkJavaClassVersions(String, String, IProgressMonitor) + */ + public int checkJavaClassVersions(MultiStatus status, Object javaClassObj1, Object javaClassObj2, IProgressMonitor monitor) throws CoreException { + try { + monitor = VersioningProgressMonitorWrapper.monitorFor(monitor); + monitor.beginTask(Messages.JavaClassVersionCompare_comparingClassMsg, 100); + finalResult = status; + // get IClassFileReader instances of javaClassObj1 and javaClassObj2 + IClassFileReader classFileReader1 = ClassFileHelper.getReader(javaClassObj1); + if (classFileReader1 == null) { + if (javaClassObj1 instanceof InputStream) + finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, Messages.JavaClassVersionCompare_inputStreamErrMsg, null)); + else + finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.JavaClassVersionCompare_classFileNotLoadedMsg, javaClassObj1), null)); + return IVersionCompare.ERROR_OCCURRED; + } + IClassFileReader classFileReader2 = ClassFileHelper.getReader(javaClassObj2); + // worked 5% + monitor.worked(5); + if (monitor.isCanceled()) + throw new OperationCanceledException(); + if (classFileReader2 == null) { + if (javaClassObj2 instanceof InputStream) + finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, Messages.JavaClassVersionCompare_inputStreamErrMsg, null)); + else + finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.PROCESS_ERROR_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.JavaClassVersionCompare_classFileNotLoadedMsg, javaClassObj2), null)); + return IVersionCompare.ERROR_OCCURRED; + } + // worked 5% + monitor.worked(5); + if (monitor.isCanceled()) + throw new OperationCanceledException(); + // initialize flags + hasError = false; + hasMajorChange = false; + hasMinorChange = false; + hasMicroChange = false; + // compare two classes ( 90% workload) + compareJavaClasses(classFileReader1, classFileReader2, new SubProgressMonitor(monitor, 90)); + // analysis result + if (hasError) { + finalResult.merge(resultStatusHandler(IStatus.ERROR, IVersionCompare.CLASS_OVERALL_STATUS | IVersionCompare.ERROR_OCCURRED, NLS.bind(Messages.JavaClassVersionCompare_classErrorOccurredMsg, charsToString(classFileReader1.getClassName())), null)); + return IVersionCompare.ERROR_OCCURRED; + } + if (hasMajorChange) { + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_OVERALL_STATUS, NLS.bind(Messages.JavaClassVersionCompare_classMajorChangeMsg, charsToString(classFileReader1.getClassName())), null)); + return IVersionCompare.MAJOR_CHANGE; + } + if (hasMinorChange) { + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_OVERALL_STATUS, NLS.bind(Messages.JavaClassVersionCompare_classMinorChangeMsg, charsToString(classFileReader1.getClassName())), null)); + return IVersionCompare.MINOR_CHANGE; + } + if (hasMicroChange) { + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_OVERALL_STATUS, NLS.bind(Messages.JavaClassVersionCompare_classMicroChange, charsToString(classFileReader1.getClassName())), null)); + return IVersionCompare.MICRO_CHANGE; + } + return IVersionCompare.NO_CHANGE; + } finally { + monitor.done(); + } + } + + /** + * compares two java classes denoted by <code>classFileReader1</code> and <code>classFileReader2</code>, + * and check if there is any change from <code>classFileReader2</code> to <code>classFileReader1</code>. + * + * @param classFileReader1 + * @param classFileReader2 + * @param monitor IProgressMonitor instance + * @return compare result IStatus instance + */ + private IStatus compareJavaClasses(IClassFileReader classFileReader1, IClassFileReader classFileReader2, IProgressMonitor monitor) { + try { + monitor.beginTask("", 100); //$NON-NLS-1$ + // compare class names + String name1 = charsToString(classFileReader1.getClassName()); + String name2 = charsToString(classFileReader2.getClassName()); + if (!name1.equals(name2)) { + finalResult.merge(resultStatusHandler(IStatus.WARNING, IVersionCompare.PROCESS_ERROR_STATUS, NLS.bind(Messages.JavaClassVersionCompare_differentClassNameMsg, name1, name2), null)); + return finalResult; + } + // worked 5% + monitor.worked(5); + // compare super classes + checkSuperClasses(name1, classFileReader1.getSuperclassName(), classFileReader2.getSuperclassName()); + // worked 5% + monitor.worked(5); + // compare interfaces + checkInterfaces(name1, generateList(classFileReader1.getInterfaceNames()), generateList(classFileReader2.getInterfaceNames())); + // worked 5% + monitor.worked(5); + // compare modifier of classes + checkClassModifiers(name1, classFileReader1.getAccessFlags(), classFileReader2.getAccessFlags()); + // worked 5% + monitor.worked(5); + // compare fields + checkElements(name1, generateTable(classFileReader1.getFieldInfos()), generateTable(classFileReader2.getFieldInfos())); + // worked 40% + monitor.worked(40); + // compare methods (40%) + checkElements(name1, generateTable(classFileReader1.getMethodInfos()), generateTable(classFileReader2.getMethodInfos())); + return finalResult; + } finally { + monitor.done(); + } + } + + /** + * checks if super class has been changed + * + * @param className name of the class we are comparing + * @param superClassName1 + * @param superClassName2 + */ + private void checkSuperClasses(String className, char[] superClassName1, char[] superClassName2) { + if (!charsToString(superClassName1).equals(charsToString(superClassName2))) { + Object[] msg = {className, charsToString(superClassName2), charsToString(superClassName1)}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_differentSuperClassMsg, msg), null)); + } + } + + /** + * checks if there is any change between <code>interfaceList1</code> and <code>interfaceList2</code> + * + * @param className name of the class we are comparing + * @param interfaceList1 List of interface name + * @param interfaceList2 List of interface name + */ + private void checkInterfaces(String className, List interfaceList1, List interfaceList2) { + for (Iterator nameIterator1 = interfaceList1.iterator(); nameIterator1.hasNext();) { + // get a name of interface from interfaceNames1 + String name1 = (String) nameIterator1.next(); + // check if the interface is in interfaceNames2 + if (!interfaceList2.remove(name1)) + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_newAddedInterfaceMsg, name1, className), null)); + } + // check what does no longer exist + for (Iterator nameIterator2 = interfaceList2.iterator(); nameIterator2.hasNext();) { + String name2 = (String) nameIterator2.next(); + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_deletedInterfaceMsg, name2, className), null)); + } + } + + /** + * checks two class modifiers to see if there is any change from <code>accessFlag2</code> to <code>accessFlag1</code> + * @param accessFlag1 + * @param accessFlag2 + */ + private void checkClassModifiers(String className, int accessFlag1, int accessFlag2) { + int change = accessFlag1 ^ accessFlag2; + if (change != 0) { + // if the visibility of a method has been narrowed, it is a change should be caught + Object[] msg = {className, createChangedModifierString(accessFlag2, change), createChangedModifierString(accessFlag1, change)}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_classModifierChangedMsg, msg), null)); + } + } + + /** + * checks corresponding elements(IMethodInfo instances or IFieldInfo instances), + * to see if there is any change + * @param className className name of class to which values in <code>elementMap1</code> + * (and <code>elementMap2</code>) belong + * @param elementMap1 map contains IMethodInfo instances or IFieldInfo instances + * @param elementMap2 map contains IMethodInfo instances or IFieldInfo instances + */ + private void checkElements(String className, Map elementMap1, Map elementMap2) { + for (Iterator iterator1 = elementMap1.keySet().iterator(); iterator1.hasNext();) { + // get a key and value from methodMap1 + String key = (String) iterator1.next(); + Object value1 = elementMap1.get(key); + // try to get the corresponding method from methodMap2 + Object value2 = elementMap2.get(key); + if (value2 != null) { + if (value1 instanceof IMethodInfo) + // compare the corresponding methods + compareMethodInfos(className, (IMethodInfo) value1, (IMethodInfo) value2); + else + // compare the corresponding fields in fieldInfoMap1 and fieldInfoMap2 + compareFieldInfos(className, (IFieldInfo) value1, (IFieldInfo) value2); + elementMap2.remove(key); + } else { + if (value1 instanceof IMethodInfo) { + if (Flags.isPublic(((IMethodInfo) value1).getAccessFlags()) || Flags.isProtected(((IMethodInfo) value1).getAccessFlags())) { + Object[] msg = new Object[] {METHOD_TITLE, getSignatureString(value1), className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MINOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_newAddedMsg, msg), null)); + } + } else { + if (Flags.isPublic(((IFieldInfo) value1).getAccessFlags()) || Flags.isProtected(((IFieldInfo) value1).getAccessFlags())) { + Object[] msg = new Object[] {FIELD_TITLE, getSignatureString(value1), className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MINOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_newAddedMsg, msg), null)); + } + } + } + } + // if there are anythings left in fieldInfoMap1, they no longer exist in the class + for (Iterator iterator2 = elementMap2.values().iterator(); iterator2.hasNext();) { + Object object = iterator2.next(); + if (object instanceof IMethodInfo) { + // we only care which is protected or public + if (Flags.isPublic(((IMethodInfo) object).getAccessFlags()) || Flags.isProtected(((IMethodInfo) object).getAccessFlags())) { + Object[] msg = new Object[] {METHOD_TITLE, getSignatureString(object), className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_noLongerExistMsg, msg), null)); + } + } else { + if (Flags.isPublic(((IFieldInfo) object).getAccessFlags()) || Flags.isProtected(((IFieldInfo) object).getAccessFlags())) { + Object[] msg = new Object[] {FIELD_TITLE, getSignatureString(object), className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_noLongerExistMsg, msg), null)); + } + } + + } + } + + /** + * compares two IMethodInfo instances to find any change from <code>method2</code> to <code>method1</code> + * + * @param className name of class to which <code>method1</code>(and <code>method2</code>) belongs + * @param method1 IMethodInfo instance + * @param method2 IMethodInfo instance + */ + private void compareMethodInfos(String className, IMethodInfo method1, IMethodInfo method2) { + // compare AccessFlags (AccessFlags defines the modifiers of a method (e.g. public static final compareTo()) + int accessFlag1 = method1.getAccessFlags(); + int accessFlag2 = method2.getAccessFlags(); + // we just care about field who was public or protected + if (!(Flags.isPublic(accessFlag2) || Flags.isProtected(accessFlag2))) + return; + if (isModifierNarrowed(accessFlag1, accessFlag2)) { + // get what modifiers have been changed + int change = accessFlag1 ^ accessFlag2; + // if the visibility of a method has been narrowed, it is a change should be caught + Object[] msg = {METHOD_TITLE, getSignatureString(method1), createChangedModifierString(accessFlag2, change), createChangedModifierString(accessFlag1, change), className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_ModifierChangedMsg, msg), null)); + } + // compare isDeprecated(if a method has been deprecated) + if (method1.isDeprecated() && !method2.isDeprecated()) { + Object[] msg = {METHOD_TITLE, getSignatureString(method1), className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MICRO_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_deprecatedChangedMsg, msg), null)); + } + // compare exceptions + IExceptionAttribute exceptionAtrributes1 = method1.getExceptionAttribute(); + IExceptionAttribute exceptionAtrributes2 = method2.getExceptionAttribute(); + checkExceptions(className, getSignatureString(method1), exceptionAtrributes1, exceptionAtrributes2); + } + + /** + * check two IExceptionAttribute instances to see if there is any change + * @param className name of the class to which the method denoted by <code>methodName</code> belongs + * @param methodName name of the method to which exceptionsAttribute1(exceptionsAttribute2) belongs + * @param exceptionsAttribute1 + * @param exceptionsAttribute2 + */ + private void checkExceptions(String className, String methodName, IExceptionAttribute exceptionsAttribute1, IExceptionAttribute exceptionsAttribute2) { + List exceptionList1 = null; + List exceptionList2 = null; + if (exceptionsAttribute1 != null && exceptionsAttribute2 != null) { + exceptionList1 = generateList(exceptionsAttribute1.getExceptionNames()); + exceptionList2 = generateList(exceptionsAttribute2.getExceptionNames()); + } else if (exceptionsAttribute1 != null) { + exceptionList1 = generateList(exceptionsAttribute1.getExceptionNames()); + } else if (exceptionsAttribute2 != null) { + exceptionList2 = generateList(exceptionsAttribute2.getExceptionNames()); + } else { + return; + } + StringBuffer newAddedExceptions = new StringBuffer(); + if (exceptionList1 != null) { + // check what is new added + for (Iterator iterator1 = exceptionList1.iterator(); iterator1.hasNext();) { + // get a exception from exceptionList1 + String exception1 = (String) iterator1.next(); + if (exceptionList2 != null) { + // check if the exception is in exceptionList2 + if (!exceptionList2.remove(exception1)) { + newAddedExceptions.append(exception1); + newAddedExceptions.append(COMMA_MARK); + } + } else { + // if exceptionList2 is null, it is new added + newAddedExceptions.append(exception1); + newAddedExceptions.append(COMMA_MARK); + } + } + if (!newAddedExceptions.toString().trim().equals(EMPTY_STRING)) { + Object[] msg = {newAddedExceptions.toString(), methodName, className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MINOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_newAddedExceptionMsg, msg), null)); + } + } + if (exceptionList2 != null) { + StringBuffer notExistExceptions = new StringBuffer(); + // check what does no longer exist + for (Iterator iterator2 = exceptionList2.iterator(); iterator2.hasNext();) { + String exception2 = (String) iterator2.next(); + notExistExceptions.append(exception2); + notExistExceptions.append(COMMA_MARK); + } + if (!notExistExceptions.toString().trim().equals(EMPTY_STRING)) { + Object[] msg2 = {notExistExceptions.toString(), methodName, className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MINOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_noLongerExistExceptionMsg, msg2), null)); + } + } + } + + /** + * checks if there is any change from <code>accessFlag2</code> to <code>accessFlag1</code> + * we check changes which narrowed down the visibility of a field or method with protected or public modifier + * + * @param accessFlag1 denotes combined modifiers of a field or method + * @param accessFlag2 denotes combined modifiers of a field or method + * @return <code>true</code> if visibility has been narrowed down from <code>accessFlag2</code> to <code>accessFlag1</code>, + * <code>false</code> otherwise + */ + private boolean isModifierNarrowed(int accessFlag1, int accessFlag2) { + if (Flags.isProtected(accessFlag2)) { + // from protected to modifier other than public and protected + if (!(Flags.isPublic(accessFlag1) || Flags.isProtected(accessFlag1))) { + return true; + } + } else if (Flags.isPublic(accessFlag2)) { + // from public to modifier other than public + if (!Flags.isPublic(accessFlag1)) { + return true; + } + } else { + // only check which was protected or public + return false; + } + // from non-final to final + if (!Flags.isFinal(accessFlag2) && Flags.isFinal(accessFlag1)) { + return true; + } + // from static to non-static + if (Flags.isStatic(accessFlag2) && !Flags.isStatic(accessFlag1)) { + return true; + } + // from non-abstract to abstract + if (!Flags.isAbstract(accessFlag2) && Flags.isAbstract(accessFlag1)) { + return true; + } + // volatile modifier changed + if (Flags.isVolatile(accessFlag2) != Flags.isVolatile(accessFlag1)) { + return true; + } + return false; + } + + /** + * check if <code>accessFlag</code> is <code>default</code> + * @param accessFlag + * @return <code>true</code> if <code>addessFlag</code> is <code>default</code>, + * <code>false</code> otherwise + */ + private boolean isDefault(int accessFlag) { + return (accessFlag & DEFAULT_MODIFIER_TESTER) == 0 ? true : false; + } + + /** + * compares two IFieldInfo instances to find any change from <code>field1</code> to <code>field2</code> + * + * @param className name of class to which <code>field1</code>(and <code>field2</code>) belongs + * @param field1 IFieldInfo instance + * @param field2 IFieldInfo instance + */ + private void compareFieldInfos(String className, IFieldInfo field1, IFieldInfo field2) { + // compare AccessFlags (AccessFlags defines the modifiers of a field (e.g. public static final IVersionCompare.PLUGIN_ID = "org.eclipse.pde.tools.versioning") + int accessFlag1 = field1.getAccessFlags(); + int accessFlag2 = field2.getAccessFlags(); + // we just care about field who was public or protected + if (!(Flags.isPublic(accessFlag2) || Flags.isProtected(accessFlag2))) { + return; + } + if (isModifierNarrowed(accessFlag1, accessFlag2)) { + // get what modifiers have been changed + int change = accessFlag1 ^ accessFlag2; + // if the visibility of a field which was public or protected has been narrowed, it is a change should be caught + Object[] msg = {FIELD_TITLE, charsToString(field1.getName()), createChangedModifierString(accessFlag2, change), createChangedModifierString(accessFlag1, change), className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_ModifierChangedMsg, msg), null)); + } + // compare Descriptor (Descriptor describes the type of a field) + String descriptor1 = charsToString(field1.getDescriptor()); + String descriptor2 = charsToString(field2.getDescriptor()); + if (!descriptor1.equals(descriptor2)) { + String[] msg = {charsToString(field1.getName()), Signature.toString(descriptor2), Signature.toString(descriptor1), className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MAJOR_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_descriptorChangedMsg, msg), null)); + } + // compare isDeprecated (if a field has been deprecated) + if (field1.isDeprecated() && !field2.isDeprecated()) { + Object[] msg = {FIELD_TITLE, charsToString(field1.getName()), className}; + finalResult.merge(resultStatusHandler(IStatus.INFO, IVersionCompare.CLASS_DETAIL_STATUS | IVersionCompare.MICRO_CHANGE, NLS.bind(Messages.JavaClassVersionCompare_deprecatedChangedMsg, msg), null)); + } + } + + /** + * creates modifier string which includes multiple modifiers(e.g. "public static final") + * + * @param accessFlags accessFlags of field or method + * @param changedFlags indicates change on accessFlags + * @return modifier string + */ + private String createChangedModifierString(int accessFlags, int changedFlags) { + StringBuffer buffer = new StringBuffer(); + if (Flags.isPublic(changedFlags)) { + if (Flags.isPublic(accessFlags)) { + buffer.append(PUBLIC_STRING); + buffer.append(SPACE); + } else if (isDefault(accessFlags)) { + buffer.append(DEFAULT_STRING); + buffer.append(SPACE); + } + } + if (Flags.isProtected(changedFlags)) { + if (Flags.isProtected(accessFlags)) { + buffer.append(PROTECTED_STRING); + buffer.append(SPACE); + } else if (isDefault(accessFlags)) { + buffer.append(DEFAULT_STRING); + buffer.append(SPACE); + } + } + if (Flags.isPrivate(changedFlags)) { + if (Flags.isPrivate(accessFlags)) { + buffer.append(PRIVATE_STRING); + buffer.append(SPACE); + } else if (isDefault(accessFlags)) { + buffer.append(DEFAULT_STRING); + buffer.append(SPACE); + } + } + if (Flags.isStatic(changedFlags)) { + if (Flags.isStatic(accessFlags)) { + buffer.append(STATIC_STRING); + buffer.append(SPACE); + } else { + buffer.append(NON_STATIC_STRING); + buffer.append(SPACE); + } + } + if (Flags.isFinal(changedFlags)) { + if (Flags.isFinal(accessFlags)) { + buffer.append(FINAL_STRING); + buffer.append(SPACE); + } else { + buffer.append(NON_FINAL_STRING); + buffer.append(SPACE); + } + } + if (Flags.isAbstract(changedFlags)) { + if (Flags.isAbstract(accessFlags)) { + buffer.append(ABSTRACT_STRING); + buffer.append(SPACE); + } else { + buffer.append(NON_ABSTRACT_STRING); + buffer.append(SPACE); + } + } + if (Flags.isVolatile(changedFlags)) { + if (Flags.isVolatile(accessFlags)) { + buffer.append(VOLATILE_STRING); + buffer.append(SPACE); + } else { + buffer.append(NON_VOLATILE_STRING); + buffer.append(SPACE); + } + } + return buffer.toString().trim(); + } + + /** + * converts char array to String + * @param chars array of char + * @return String which represents the content of <code>chars</code> + */ + private String charsToString(char[] chars) { + return new String(chars); + } + + /** + * generates a List which stores instances in array <code>objects</code> + * + * @param objects instance objects + * @return List + */ + private List generateList(Object[] objects) { + ArrayList list = new ArrayList(0); + if (objects == null || objects.length == 0) + return list; + if (objects[0] instanceof char[]) + for (int i = 0; i < objects.length; i++) + list.add(charsToString((char[]) objects[i])); + else + for (int i = 0; i < objects.length; i++) + list.add(objects[i]); + return list; + } + + /** + * converts the given object signature to a readable string + * @param object IFieldInfo instance of IMethodInfo instance + * @return String type signature + */ + private String getSignatureString(Object object) { + StringBuffer buffer = new StringBuffer(); + if (object instanceof IMethodInfo) { + IMethodInfo method = (IMethodInfo) object; + buffer.append(Flags.toString(method.getAccessFlags())); + buffer.append(SPACE); + buffer.append(Signature.toString(charsToString(method.getDescriptor()), charsToString(method.getName()), null, false, true)); + } else { + IFieldInfo field = (IFieldInfo) object; + buffer.append(Flags.toString(field.getAccessFlags())); + buffer.append(SPACE); + buffer.append(Signature.toString(charsToString(field.getDescriptor()))); + buffer.append(SPACE); + buffer.append(charsToString(field.getName())); + } + return buffer.toString(); + } + + /** + * generates a map which stores IField instances or IMethod instances + * + * @param objects array of IMethodInfo or IFieldInfo instances + * @return Map instance contains IField instances or IMethod instances + */ + private Map generateTable(Object[] objects) { + Hashtable hashTable = new Hashtable(0); + if (objects == null || objects.length == 0) { + return hashTable; + } + // set hashtable + if (objects[0] instanceof IFieldInfo) { + for (int i = 0; i < objects.length; i++) { + if (objects[i] != null) + hashTable.put(charsToString(((IFieldInfo) objects[i]).getName()), objects[i]); + } + } else if (objects[0] instanceof IMethodInfo) { + for (int i = 0; i < objects.length; i++) { + if (objects[i] != null) + hashTable.put(getMethodKey((IMethodInfo) objects[i]), objects[i]); + } + } + return hashTable; + } + + /** + * get key of a method. Key of a method is a String which + * includes the retype of the method,name of the method and the parameter types of the method + * (e.g. key of public int foo(int , String) is "int#foo#int#String" + * @param method + * @return key of a method + */ + private String getMethodKey(IMethodInfo method) { + StringBuffer buffer = new StringBuffer(); + // append return type + buffer.append(method.getDescriptor()); + // append name of method + buffer.append(charsToString(method.getName())); + char[][] parameters = Signature.getParameterTypes(method.getDescriptor()); + // append parameter types + if (parameters != null) { + for (int i = 0; i < parameters.length; i++) { + buffer.append(KEY_SEPARATOR); + buffer.append(charsToString(parameters[i])); + } + } + return buffer.toString(); + } + + /** + * Return a new status object populated with the given information. + * + * @param severity severity of status + * @param code indicates type of this IStatus instance, it could be one of: FEATURE_OVERALL_STATUS, + * FEATURE_DETAIL_STATUS, PLUGIN_OVERALL_STATUS, PLUGIN_DETAIL_STATUS, PROCESS_ERROR_STATUS, + * CLASS_OVERALL_STATUS, CLASS_DETAIL_STATUS + * @param message the status message + * @param exception exception which has been caught, or <code>null</code> + * @return the new status object + */ + private IStatus resultStatusHandler(int severity, int code, String message, Exception exception) { + processed(code); + + if (message == null) { + if (exception != null) + message = exception.getMessage(); + // extra check because the exception message can be null + if (message == null) + message = EMPTY_STRING; + } + return new Status(severity, PLUGIN_ID, code, message, exception); + } + + /** + * checks what kind of change does <code>code</code> represent + * @param code + */ + private void processed(int code) { + if ((code & IVersionCompare.ERROR_OCCURRED) != 0){ + hasError = true; + return; + } + if ((code & IVersionCompare.MAJOR_CHANGE) != 0){ + hasMajorChange = true; + return; + } + if ((code & IVersionCompare.MINOR_CHANGE) != 0){ + hasMinorChange = true; + return; + } + if ((code & IVersionCompare.MICRO_CHANGE) != 0) + hasMicroChange = true; + } +} |