| /******************************************************************************* |
| * 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; |
| } |
| } |