|
What this is
Other links
The source code/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.java.codesync; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.lang.reflect.Modifier; import java.util.*; import org.netbeans.jmi.javamodel.ClassDefinition; import org.netbeans.jmi.javamodel.JavaClass; import org.netbeans.jmi.javamodel.JavaModelPackage; import org.netbeans.jmi.javamodel.Parameter; import org.netbeans.jmi.javamodel.ParameterClass; import org.netbeans.jmi.javamodel.ParameterizedType; import org.netbeans.jmi.javamodel.ParameterizedTypeClass; import org.netbeans.jmi.javamodel.Resource; import org.netbeans.jmi.javamodel.TypeClass; import org.netbeans.modules.javacore.jmiimpl.javamodel.ParameterizedTypeImpl.Wrapper; import org.openide.NotifyDescriptor; import org.openide.cookies.SourceCookie; import org.openide.src.*; import org.openide.util.RequestProcessor; import org.openide.util.Task; import org.openide.util.TaskListener; import org.netbeans.modules.java.bridge.CommitListener; import org.netbeans.modules.java.JavaConnections; import org.netbeans.modules.java.JavaConnections.ChangeProcessor; import org.netbeans.modules.java.settings.JavaSynchronizationSettings; import org.netbeans.api.java.comparators.JavaElementComparator; import org.netbeans.jmi.javamodel.Method; import org.netbeans.modules.java.tools.JMIInheritanceSupport; import org.netbeans.modules.java.tools.JMIInheritanceSupport.MethodKey; import org.netbeans.modules.javacore.internalapi.JMIElementCookie; import org.netbeans.modules.javacore.internalapi.JavaMetamodel; import org.openide.DialogDisplayer; import org.openide.filesystems.FileObject; import org.openide.loaders.DataObject; /** * This class implements a dependency manager between a class and its ancestors. * Currently, the implementation is designed as a stateless helper that only separates * class-related logic from registration logic (located in {@link SourceConnectionSupport}). * It is possible, that the class will be converted into stateful (with the ClassElement bean * as the state info) and will manage only the bean's dependencies. * * @author sdedic * @version */ class ClassDependencyImpl implements PropertyChangeListener, CommitListener { private static final int MODIFIERS_ACCESS = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE; private static org.netbeans.modules.java.ui.nodes.elements.ElementFormat methodFormat; private static final boolean DEBUG = false; Registrar registrar; private JavaSynchronizationSettings SYNC_SETTINGS = null; private static Comparator CHANGEITEM_COMPARATOR; public ClassDependencyImpl(Registrar r) { if (SYNC_SETTINGS==null) SYNC_SETTINGS=(JavaSynchronizationSettings)JavaSynchronizationSettings.findObject(JavaSynchronizationSettings.class,true); if (CHANGEITEM_COMPARATOR == null) CHANGEITEM_COMPARATOR = new ChangeItemComparator(); this.registrar = r; } private Collection getDirectSupertypes(ClassElement c) { Collection col = new LinkedList(); col.addAll(Arrays.asList(c.getInterfaces())); if (c.getSuperclass() != null) { col.add(c.getSuperclass()); } return col; } private void destroy(ClassElement c) { if (DEBUG) System.err.println("Class " + c.getName().getFullName() + " destructed."); // NOI18N Collection col = getDirectSupertypes(c); supertypesRemoved(c, col); // detach from the class - it is gone for good. c.removePropertyChangeListener(this); } private void registerNewClass(ClassElement c) { if (DEBUG) System.err.println("Class " + c.getName().getFullName() + " constructed."); // NOI18N Collection col = getDirectSupertypes(c); supertypesAdded(c, col, false); c.addPropertyChangeListener(this); } ///////////////////////////////////////////////////////////////////////////// public void propertyChange(PropertyChangeEvent evt) { String propName = evt.getPropertyName(); if (ElementProperties.PROP_INTERFACES.equals(propName)) interfacesChanged(evt); else if (ElementProperties.PROP_SUPERCLASS.equals(propName)) superclassChanged((ClassElement)evt.getSource(), (Identifier)evt.getOldValue(), (Identifier)evt.getNewValue()); else if (ElementProperties.PROP_CLASS_OR_INTERFACE.equals(propName)) { ClassElement c = (ClassElement)evt.getSource(); if (c.isClassOrInterface()) { supertypesAdded(c, getDirectSupertypes(c), false); } } } /** * Does a full refresh on a particular class' data. Mainly used when the class * is first seen (not constructed) in the source - e.g. after the first parse. */ public void refreshClass(ClassElement c, boolean first) { if (DEBUG) System.err.println("Refreshing class " + c.getName().getFullName()); // NOI18N if (!first) { Collection sups = getDirectSupertypes(c); supertypesAdded(c, sups, first); } // just in case synchronized (this) { c.removePropertyChangeListener(this); c.addPropertyChangeListener(this); } } void synchronizeClass(ClassElement target) { JMIElementCookie cookie = (JMIElementCookie) target.getCookie(JMIElementCookie.class); if (cookie == null) return; ClassDefinition cd = (ClassDefinition) cookie.getElement(); if ((cd instanceof JavaClass) && ((JavaClass) cd).isInterface()) return; // do not synchronize interfaces List interfaces = cd.getInterfaces(); Collection c = new ArrayList(interfaces.size() + 1); for (Iterator iter = interfaces.iterator(); iter.hasNext(); ) { c.add(iter.next()); } JavaClass superClass = cd.getSuperClass(); if (superClass != null) c.add(superClass); // get the metadata in sync with the current state. supertypesAdded(target, c, true); String caption = java.text.MessageFormat.format( getString("MSG_SynchronizeExplicit"), // NOI18N new Object[] { target.getName().getFullName(), "" // NOI18N }); // nevertheless, synchronize! Synchronizer sync = new Synchronizer(target, c); sync.overrideDisable(); sync.setCaption(caption); RequestProcessor.postRequest(sync); } private class Synchronizer implements Runnable { ClassElement target; Collection superIDs; boolean overrideDisable; int mode; Collection changeList; String caption; Synchronizer(ClassElement target, Collection superIDs) { this.target = target; this.superIDs = superIDs; this.mode = 1; } Synchronizer(Collection changeList) { this.changeList = changeList; this.mode = 2; } public void overrideDisable() { overrideDisable = true; } public void setCaption(String caption) { this.caption = caption; } public void run() { switch (mode) { case 1: collectSupertypeMethods(); break; case 2: confirmChanges(); } } private void collectSupertypeMethods() { if (DEBUG) System.err.println("collecting supertype methods"); // NOI18N Collection c = implementFromSuper(target, superIDs); if (c == null || c.isEmpty()) return; applyChanges(target, caption, c, overrideDisable); } private void confirmChanges() { autoApplyChanges(changeList); } } /** * Handles action(s) for removed interfaces. Removes them from the * "registered set", mainly. */ protected void supertypesRemoved(ClassElement c, Collection removed) { for (Iterator it = removed.iterator(); it.hasNext(); ) { Identifier id = (Identifier)it.next(); if (DEBUG) System.err.println("Removing dependency: " + c.getName().getFullName() + " -> " + id.getFullName()); // NOI18N registrar.removeDependency(c, id); } } protected void supertypesAdded(final ClassElement c, final Collection added, boolean refreshOnly) { Collection resolved = null; if (c.isClass()) { for (Iterator it = added.iterator(); it.hasNext(); ) { Object obj = it.next(); Identifier id = null; if (obj instanceof JavaClass) { ClassElement clsElem = getClassElement((JavaClass) obj); id = clsElem.getName(); } else { id = (Identifier)obj; String fqn = id.getFullName(); int index = fqn.indexOf('<'); if (index > -1) { id = Identifier.create(fqn.substring(0, index)); } } if (resolved == null) resolved = new LinkedList(); if (registrar.addDependency(c, id)) { resolved.add(id); } } } if (resolved == null || resolved.isEmpty()) return; if (refreshOnly || !c.isClassOrInterface() || (c.getModifiers() & Modifier.ABSTRACT) > 0) return; // PENDING: handle new interfaces. int syncMode = getSynchronizationMode(c); if (syncMode == SourceConnectionSupport.CONNECT_NOT) return; String caption = java.text.MessageFormat.format( getString("MSG_SynchronizeAddInterfaces"), // NOI18N new Object[] { c.getName().getFullName(), "" // NOI18N }); Synchronizer sync = new Synchronizer(c, resolved); sync.setCaption(caption); RequestProcessor.postRequest(sync); } private void interfacesChanged(PropertyChangeEvent evt) { MultiPropertyChangeEvent e = (MultiPropertyChangeEvent)evt; MultiPropertyChangeEvent addEvent = null, removeEvent = null; for (Iterator changes = (Iterator)e.getIterator(); changes.hasNext(); ) { MultiPropertyChangeEvent part = (MultiPropertyChangeEvent)changes.next(); int type = part.getEventType(); if (type == MultiPropertyChangeEvent.TYPE_REMOVE) { removeEvent = part; } else if (type == MultiPropertyChangeEvent.TYPE_ADD) { addEvent = part; } } if (removeEvent != null) supertypesRemoved((ClassElement)evt.getSource(), removeEvent.getAffectedItems()); if (addEvent != null) supertypesAdded((ClassElement)evt.getSource(), addEvent.getAffectedItems(), false); } public boolean dependsOn(ClassElement c, Identifier id) { Identifier s = c.getSuperclass(); if (id == null) return false; if (s != null && s.compareTo(id, false)) return true; Identifier[] ss = c.getInterfaces(); for (int i = 0; i < ss.length; i++) { s = ss[i]; if (s.compareTo(id, false)) return true; } return false; } private void superclassChanged(ClassElement c, Identifier old, Identifier now) { if (old != null) supertypesRemoved(c, Collections.singletonList(old)); if (now != null) supertypesAdded(c, Collections.singletonList(now), false); } public void changesCommited(Set added, Set removed, Map changed) { if (removed != null) { for (Iterator it = removed.iterator(); it.hasNext(); ) { Element el = (Element)it.next(); if (!(el instanceof ClassElement)) continue; ClassElement c = (ClassElement)el; destroy(c); } } if (added != null) { for (Iterator it = added.iterator(); it.hasNext(); ) { Element el = (Element)it.next(); if (!(el instanceof ClassElement)) continue; ClassElement c = (ClassElement)el; registerNewClass(c); } } } private static Method findMatchingMethod(ClassDefinition jmiClazz, Method jmiElem, boolean superclasses, boolean acceptAbstract) { List params = jmiElem.getParameters(); List paramTypes = new ArrayList(params.size()); for (Iterator iter = params.iterator(); iter.hasNext(); ) { paramTypes.add(((org.netbeans.jmi.javamodel.Parameter) iter.next()).getType()); } Method m = jmiClazz.getMethod(jmiElem.getName(), paramTypes, false); // if we do not accept abstract methods and the method is, invalidate if (!acceptAbstract && (m != null && (m.getModifiers() & Modifier.ABSTRACT) > 0)) { m = null; } // end the search if a method was found, or the search should not // continue to parents. if (m != null || !superclasses) return m; jmiClazz = jmiClazz.getSuperClass(); if (jmiClazz == null) return null; return findMatchingMethod(jmiClazz, jmiElem, superclasses, false); } private static Method findMatchingMethod(ClassDefinition jmiClazz, MethodElement elem, MethodElement newElem, Method newMethod, boolean superclasses, boolean acceptAbstract) { MethodParameter[] params = elem.getParameters(); MethodParameter[] newParams = newElem.getParameters(); String[] typeNames = new String [params.length]; boolean sameParams = params.length == newParams.length; if (sameParams) { for (int x = 0; x < params.length; x++) { if (!newParams[x].getType().getFullString().equals(params[x].getType().getFullString())) { sameParams = false; break; } } } if (sameParams) { Iterator it = newMethod.getParameters().iterator(); for (int x = 0; it.hasNext(); x++) { typeNames[x] = ((Parameter) it.next()).getType().getName(); } } else { for (int x = 0; x < params.length; x++) { typeNames[x] = params[x].getType().getFullString(); } } return findMatchingMethod(jmiClazz, typeNames, elem.getName().getName(), superclasses, acceptAbstract); } private static Method findMatchingMethod(ClassDefinition jmiClazz, String[] typeNames, String name, boolean superclasses, boolean acceptAbstract) { Method m = null; for (Iterator iter = jmiClazz.getContents().iterator(); iter.hasNext(); ) { Object o = iter.next(); if (o instanceof Method) { Method m_1 = (o instanceof Wrapper) ? (Method)((Wrapper) o).getWrappedObject() : (Method)o; if (!name.equals(m_1.getName())) continue; List pars = m_1.getParameters(); if (typeNames.length != pars.size()) continue; boolean matches = true; Iterator it = pars.iterator(); for (int i = 0; i < typeNames.length; i++) { String tName = ((Parameter)it.next()).getType().getName(); if (!typeNames[i].equals(tName)) { matches = false; break; } } if (matches) { m = m_1; break; } } } // if we do not accept abstract methods and the method is, invalidate if (!acceptAbstract && (m != null && (m.getModifiers() & Modifier.ABSTRACT) > 0)) { m = null; } // end the search if a method was found, or the search should not // continue to parents. if (m != null || !superclasses) return m; jmiClazz = jmiClazz.getSuperClass(); if (jmiClazz == null) return null; return findMatchingMethod(jmiClazz, typeNames, name, superclasses, false); } private static ClassDefinition findMatchingClass(ClassDefinition target, ClassDefinition cd) { List interfaces = target.getInterfaces(); List supers = new ArrayList(interfaces.size() + 1); supers.addAll(interfaces); JavaClass superCls = target.getSuperClass(); if (superCls != null) supers.add(superCls); for (Iterator iter = supers.iterator(); iter.hasNext(); ) { JavaClass jc = (JavaClass) iter.next(); JavaClass jcls = jc instanceof ParameterizedType ? ((ParameterizedType) jc).getDefinition() : jc; if (jcls == cd) return jc; } for (Iterator iter = supers.iterator(); iter.hasNext(); ) { JavaClass jc = (JavaClass) iter.next(); ClassDefinition res = findMatchingClass(jc, cd); if (res != null) return res; } return null; } private static Method findMethod(ClassDefinition jc, Method ns) { for (Iterator iter = jc.getContents().iterator(); iter.hasNext(); ) { Object o = iter.next(); if (o instanceof Method) { Method m_1 = (o instanceof Wrapper) ? (Method)((Wrapper) o).getWrappedObject() : (Method)o; if (m_1 == ns) { return (Method)o; } } } return null; } private static ClassElement getClassElement(ClassDefinition cd) { if (cd instanceof ParameterizedType) { cd = ((ParameterizedType) cd).getDefinition(); } DataObject dobj = JavaMetamodel.getManager().getDataObject(cd.getResource()); SourceCookie sourceCookie = (SourceCookie) dobj.getCookie(SourceCookie.class); if (sourceCookie == null) return null; SourceElement selem = sourceCookie.getSource(); ClassElement[] cls = selem.getClasses(); for (int x = 0; x < cls.length; x++) { if (cd == ((JMIElementCookie)cls[x].getCookie(JMIElementCookie.class)).getElement()) return cls[x]; ClassElement res = findInnerClass(cls[x], cd); if (res != null) return res; } return null; } private static ClassElement findInnerClass(ClassElement c, ClassDefinition cd) { ClassElement[] inners = c.getClasses(); for (int x = 0; x < inners.length; x++) { if (cd == ((JMIElementCookie)inners[x].getCookie(JMIElementCookie.class)).getElement()) return inners[x]; ClassElement res = findInnerClass(inners[x], cd); if (res != null) return res; } return null; } public static MethodElement getMethodElement(ClassElement clazz, Method m, ClassDefinition cd) { int index = -1; boolean found = false; for (Iterator iter = cd.getContents().iterator(); iter.hasNext(); ) { Object obj = iter.next(); if (obj instanceof Method) { index++; if (obj == m) { found = true; break; } } } MethodElement[] melems = clazz.getMethods(); return found ? melems[index] : null; } public static ClassElement forName(String name, TypeClass typeProxy, ParameterizedTypeClass ptypeProxy) { JavaClass jc = resolve(name, typeProxy, ptypeProxy); if (jc == null) return null; return getClassElement(jc); } private static JavaClass resolve(String fullName, TypeClass typeProxy, ParameterizedTypeClass ptypeProxy) { int index = fullName.indexOf('<'); if (index == -1) { return (JavaClass)typeProxy.resolve(fullName); } JavaClass jc = (JavaClass)typeProxy.resolve(fullName.substring(0, index)); List arguments = new LinkedList(); int size = fullName.length(); int i = index + 1; int level = 0; while (i < size && level >= 0) { char c = fullName.charAt(i); switch (c) { case '<': level++; break; case '>': if (level == 0) { arguments.add(resolve(fullName.substring(index + 1, i), typeProxy, ptypeProxy)); } level--; break; case ',': if (level == 0) { arguments.add(resolve(fullName.substring(index + 1, i), typeProxy, ptypeProxy)); index = i; } } // switch i++; } // while return ptypeProxy.resolveParameterizedType(jc, arguments, null); // [PENDING] outerclass param ?? } private static class AddProcessor extends ChangeProcessor { private ClassDefinition targetClass; Method addMethod; private SourceException excpt; AddProcessor(String description, Method m, ClassDefinition target, MethodElement model) { super(description, model); addMethod = m; targetClass = target; } public void process() { JMIInheritanceSupport is = new JMIInheritanceSupport(targetClass); is.overrideMethod(addMethod, true, false); } } private static class UpdateProcessor extends ChangeProcessor { private Method target; Method m; UpdateProcessor(String message, Method target, Method m, MethodElement melem) { super(message, melem); this.target = target; this.m = m; } public void process() { // update modifiers, if necessary: int mods = target.getModifiers() & ~ (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE); if (((JavaClass)m.getDeclaringClass()).isInterface()) { mods |= m.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE); mods &= ~Modifier.ABSTRACT; } else { mods |= Modifier.PUBLIC; } target.setModifiers(mods); // update name: target.setName(m.getName()); // update return type target.setType(m.getType()); // update parameters: JavaModelPackage modelPackage = (JavaModelPackage)target.refImmediatePackage(); ParameterClass parProxy = modelPackage.getParameter(); List pars1 = target.getParameters(); List pars2 = m.getParameters(); List targetPars = null; if (pars2.size() != pars1.size()) targetPars = duplicateParameters(pars2, parProxy); else { Iterator it_1 = pars1.iterator(); Iterator it_2 = pars2.iterator(); int size = pars1.size(); for (int i = 0; i < size; i++) { Parameter p1 = (Parameter) it_1.next(); Parameter p2 = (Parameter) it_2.next(); if (!p1.getType().equals(p2.getType())) { targetPars = duplicateParameters(pars2, parProxy); break; } } } if (targetPars != null) { pars1.clear(); pars1.addAll(targetPars); } } } private static List duplicateParameters(List params, ParameterClass parProxy) { List result = new ArrayList(params.size()); for (Iterator iter = params.iterator(); iter.hasNext(); ) { Parameter p = (Parameter) iter.next(); Parameter newPar = parProxy.createParameter( p.getName(), null, p.isFinal(), null, 0, p.isVarArg() ); newPar.setType(p.getType()); result.add(newPar); } return result; } private static String getString(String key) { return SourceConnectionSupport.getString(key); } private static ChangeProcessor createUpdateProcessor(Method desired, Method c, Method found, MethodElement model) { boolean same = true; int access; same = desired.getName().equals(found.getName()) && desired.getType().getName().equals(found.getType().getName()) && desired.getParameters().size() == found.getParameters().size(); ClassDefinition cd = desired.getDeclaringClass(); if (cd instanceof JavaClass && ((JavaClass) cd).isInterface()) { access = desired.getModifiers() & MODIFIERS_ACCESS; // PENDING: have the implementing class obey access rules!! } else { access = Modifier.PUBLIC; } int foundAccess = found.getModifiers() & MODIFIERS_ACCESS; same &= (foundAccess == access) || (foundAccess == Modifier.PUBLIC && access == Modifier.PROTECTED) || (foundAccess == Modifier.PROTECTED && access == 0); if (same) { Iterator pars1 = desired.getParameters().iterator(); Iterator pars2 = found.getParameters().iterator(); while (same && pars1.hasNext()) { same = ((Parameter)pars1.next()).getType().getName().equals( ((Parameter)pars2.next()).getType().getName()); } } if (same) return null; /* if (c == null) c = (Method)desired.duplicate(); c.setModifiers((found.getModifiers() & ~MODIFIERS_ACCESS) | access); // bugfix #27614 -- javadocs should not be syncrhonized c.setJavadoc(null); */ String updateFormat= getString("MSG_UpdateMethod"); // NOI18N String msg = java.text.MessageFormat.format(updateFormat, new Object[] { formatMethod(found), formatMethod(desired), desired.getDeclaringClass().getName() }); return new UpdateProcessor(msg, found, desired, model); } private static ChangeProcessor createAddProcessor(ClassDefinition target, Method t, MethodElement model) { // don't add nonabstract methods of superclasses ClassDefinition cd = t.getDeclaringClass(); boolean isClass = !(cd instanceof JavaClass) || !((JavaClass) cd).isInterface(); if (isClass && (t.getModifiers() & Modifier.ABSTRACT) == 0) return null; /* if (t.getDeclaringClass().isInterface()) { c.setModifiers( (c.getModifiers() & ~(Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE)) | Modifier.PUBLIC ); } */ // [PENDING] String addMessageFormat = getString("MSG_AddMethod"); // NOI18N String msg = java.text.MessageFormat.format(addMessageFormat, new Object[] { cd.getName(), formatMethod(t) } ); return new AddProcessor(msg, t, target, model); } private static String formatMethod(Method m) { if (methodFormat == null) { methodFormat = new org.netbeans.modules.java.ui.nodes.elements.ElementFormat(getString("FMT_MethodSignature")); } return methodFormat.format(m); } public void connectionNotify(ClassElement target, ClassElement source, Enumeration newItems, Enumeration changeEvents) { if (DEBUG) { System.err.println("[" + target.getName().getFullName() + "] got connectionNotify. "); // NOI18N } int syncMode = getSynchronizationMode(target); if (syncMode == SourceConnectionSupport.CONNECT_NOT) return; if (!target.isClassOrInterface()) return; final Collection changes = synchronizeMethods(target, newItems, changeEvents, true); if (DEBUG) { if (changes == null) { System.err.println("no changes required"); // NOI18N } else System.err.println("identified " + changes.size() + " changes"); // NOI18N } if (changes == null || changes.isEmpty()) return; final String caption = java.text.MessageFormat.format(getString("MSG_SynchronizeCaption"), new Object[] { target.getName().getFullName(), source.getName().getFullName() }); if (DEBUG) { System.err.println("caption for the dialog = " + caption); // NOI18N } applyChanges(target, caption, changes); } private void applyChanges(final ClassElement target, final String caption, final Collection changes) { applyChanges(target, caption, changes, false); } private void applyChanges(final ClassElement target, final String caption, Collection changes, boolean ignoreNot) { final int syncMode = getSynchronizationMode(target); if (!ignoreNot && (syncMode == SourceConnectionSupport.CONNECT_NOT || !SYNC_SETTINGS.isEnabled())) return; Collections.sort((List)changes,CHANGEITEM_COMPARATOR); if (syncMode == SourceConnectionSupport.CONNECT_AUTO) { RequestProcessor.postRequest(new Synchronizer(changes)); } else { List l = new ArrayList(changes); JavaConnections.SyncRequest req = JavaConnections.scheduleShowChangesDialog( caption, l, (byte)syncMode); req.getTask().addTaskListener(new SyncRequestListener(target, req)); } } private void autoApplyChanges(Collection changes) { Collection failed = null; for (Iterator it = changes.iterator(); it.hasNext(); ) { ChangeProcessor proc = (ChangeProcessor)it.next(); try { proc.process(); } catch (SourceException ex) { if (failed == null) failed = new LinkedList(); failed.add(proc); } } if (failed == null) return; StringBuffer sb = new StringBuffer(java.text.MessageFormat.format( getString("MSG_ChangesFailed"), new Object[] { new Integer(failed.size()) })); for (Iterator it = failed.iterator(); it.hasNext(); ) { sb.append('\n'); sb.append(((ChangeProcessor)it.next()).getDisplayName()); } NotifyDescriptor desc = new NotifyDescriptor.Message(sb.toString(), NotifyDescriptor.WARNING_MESSAGE); DialogDisplayer.getDefault().notify(desc); } private class SyncRequestListener implements TaskListener { JavaConnections.SyncRequest request; ClassElement target; SyncRequestListener(ClassElement t, JavaConnections.SyncRequest r) { request = r; target = t; } public void taskFinished(Task t) { t.removeTaskListener(this); setSynchronizationMode(target, request.getSyncType()); } } private static class ChangeItemComparator implements Comparator { private static Comparator METHOD_COMPARATOR; ChangeItemComparator() { if (METHOD_COMPARATOR == null) METHOD_COMPARATOR = JavaElementComparator.createConstructorComparator(true, new int[] {JavaElementComparator.NAME | JavaElementComparator.PARAMETERS}); } public int compare(Object obj, Object obj1) { Method m1 = null; Method m2 = null; if (obj instanceof UpdateProcessor) { m1 = ((UpdateProcessor) obj).m; } else { m1 = ((AddProcessor) obj).addMethod; } if (obj1 instanceof UpdateProcessor) { m2 = ((UpdateProcessor) obj1).m; } else { m2 = ((AddProcessor) obj1).addMethod; } String s1 = m1.getName(); String s2 = m2.getName(); int code = s1.compareTo(s2); if (code != 0) return code; List params1 = m1.getParameters(); List params2 = m2.getParameters(); if (params1.size() < params2.size()) { return -1; } else if (params1.size() > params2.size()) { return 1; } Iterator iter1 = params1.iterator(); Iterator iter2 = params2.iterator(); while (iter1.hasNext()) { org.netbeans.jmi.javamodel.Type t1 = ((Parameter)iter1.next()).getType(); org.netbeans.jmi.javamodel.Type t2 = ((Parameter)iter2.next()).getType(); if (!t1.equals(t2)) { return t1.getName().compareTo(t2.getName()); } } return 0; } } protected Collection synchronizeMethods(ClassElement target, Enumeration neededMethods, boolean deepScan) { return synchronizeMethods(target, neededMethods, null, deepScan); } public Collection synchronizeMethods(ClassElement target, Enumeration newItems, Enumeration changeEvents, boolean deepScan) { ClassDefinition cd = (ClassDefinition) ((JMIElementCookie) target.getCookie(JMIElementCookie.class)).getElement(); return synchronizeMethods(cd, newItems, null, changeEvents, deepScan); } /** * Attempts to synchronized the class' implementation with the passed information. * @param newItems new methods that should be inserted into the class. * @param changeEvents list of changes that should be applied to the class. */ private Collection synchronizeMethods(ClassDefinition target, Enumeration newItems, Enumeration modItems, Enumeration changeEvents, boolean deepScan) { // for new items, try to locate the method in the target class. Collection changes = null; if (newItems != null) { while (newItems.hasMoreElements()) { Object o = newItems.nextElement(); Object mo = modItems != null && modItems.hasMoreElements() ? modItems.nextElement() : null; Method m = null; Method c = null; Method m_1 = null; MethodElement model = null; ClassElement celem = null; if (o instanceof MethodElement) { model = (MethodElement)o; celem = model.getDeclaringClass(); m_1 = (Method)((JMIElementCookie)model.getCookie(JMIElementCookie.class)).getElement(); if (mo instanceof MethodElement) { MethodElement moel = (MethodElement) mo; c = (Method)((JMIElementCookie)moel.getCookie(JMIElementCookie.class)).getElement(); } ClassDefinition cd = findMatchingClass(target, m_1.getDeclaringClass()); m = findMethod(cd, m_1); } else if (o instanceof Method) { m = (Method)o; c = (Method)mo; m_1 = (m instanceof Wrapper) ? (Method)((Wrapper) m).getWrappedObject() : m; ClassDefinition declClass = m_1.getDeclaringClass(); if (m != m_1 && declClass == m.getDeclaringClass()) { m_1 = m; } celem = getClassElement(declClass); // [PENDING] model = getMethodElement(celem, m_1, declClass); } else { continue; } Method found = findMatchingMethod(target, m, deepScan, true); ChangeProcessor proc = null; // PENDING: what if the method is abstract ?? if (found != null) { // now, the method may have been in one of the ancestors. // this IS a problem, since if it is not EXACTLY the same (exception ids) // we cannot modify it. if (found.getDeclaringClass() != target) { continue; } proc = createUpdateProcessor(m, c, found, model); if (proc == null) { // PENDING: link found to m so that the dependency can // be maintained over time. continue; } // the method IS present, but is slightly different. } else { proc = createAddProcessor(target, m, model); } if (proc != null) { if (changes == null) changes = new LinkedList(); changes.add(proc); } } } // new items have been created. Now consult the changed ones. if (changeEvents != null) { while (changeEvents.hasMoreElements()) { JavaConnections.Change ch = (JavaConnections.Change)changeEvents.nextElement(); if (ch.getChangeType() != JavaConnections.TYPE_METHODS_CHANGE) { continue; } MethodElement oldStateElem = (MethodElement)ch.getOldElement(); MethodElement newStateElem = (MethodElement)ch.getNewElement(); // Method oldState = (Method) ((JMIElementCookie) oldStateElem.getCookie(JMIElementCookie.class)).getElement(); Method ns = (Method) ((JMIElementCookie) newStateElem.getCookie(JMIElementCookie.class)).getElement(); ClassDefinition jc = ns.getDeclaringClass(); jc = findMatchingClass(target, jc); Method newState = findMethod(jc, ns); ChangeProcessor proc = null; // first, try to search for the new method element, it may be present. Method found = findMatchingMethod(target, newState, deepScan, true); if (found != null) { if (target != found.getDeclaringClass()) { // something bad -- possibly conflicting method in a superclass. // PENDING: warn the user. continue; } proc = createUpdateProcessor(newState, null, found, oldStateElem); if (proc == null) { // the method is identical. // PENDING: link the method to the discovered super's one. continue; } } else if ((found = findMatchingMethod(target, oldStateElem, newStateElem, newState, deepScan, true)) != null) { if (target != found.getDeclaringClass()) { // if uncompatible, it can pose a problem. // PENDING: warn the user, if this is the case. continue; } proc = createUpdateProcessor(newState, null, found, oldStateElem); if (proc == null) { // huh ? exactly the same method ? continue; } } else { proc = createAddProcessor(target, newState, oldStateElem); } if (proc != null) { if (changes == null) changes = new LinkedList(); changes.add(proc); } } } return changes; } private void addSupertypeMethods_old(ClassElement c, Map methods, Map modMethods, Set seen, FileObject source) { if (c == null) return; if (seen.contains(c.getName().getFullName())) return; seen.add(c.getName().getFullName()); if (c == null) return; Resource resource = JavaMetamodel.getManager().getResource(source); MethodElement[] ms = c.getMethods(); boolean clazz = c.isClassOrInterface(); if (DEBUG) { System.err.println("Collecting supertypes of " + c.getName().getFullName()); // NOI18N } ClassDefinition cd = (ClassDefinition) ((JMIElementCookie) c.getCookie(JMIElementCookie.class)).getElement(); for (Iterator iter = cd.getInterfaces().iterator(); iter.hasNext(); ) { addSupertypeMethods((ClassDefinition) iter.next(), methods, modMethods, seen); } if (clazz && cd.getSuperClass() != null) { // adds all superclass' abstract methods. addSupertypeMethods(cd.getSuperClass(), methods, modMethods, seen); } if (DEBUG) { System.err.println("Adding methods of " + c.getName().getFullName()); // NOI18N } for (int i = 0; i < ms.length; i++) { MethodElement m = ms[i]; MethodElement.Key key = new MethodElement.Key(m); if (!clazz || ((m.getModifiers() & Modifier.ABSTRACT) > 0)) { if (methods.containsKey(key)) { if (DEBUG) { System.err.println("Method" + ModelEventAdapter.reportElementID(m) + " already recorded"); // NOI18N } continue; } methods.put(key, m); modMethods.put(key, m); if (DEBUG) { System.err.println("Adding " + ModelEventAdapter.reportElementID(m)); // NOI18N } } else { if (DEBUG) { System.err.println("Implemented " + ModelEventAdapter.reportElementID(m)); // NOI18N } // un-register the method: if (methods.remove(key) != null) { modMethods.remove(key); if (DEBUG) { System.err.println("-- removing from list."); // NOI18N } } } } if (DEBUG) { System.err.println("Done processing of " + c.getName().getFullName()); // NOI18N } } private void addSupertypeMethods(ClassDefinition c, Map methods, Map modMethods, Set seen) { if (c == null) return; if (seen.contains(c)) return; seen.add(c); Resource resource = c.getResource(); boolean isClazz = !(c instanceof JavaClass) || !((JavaClass) c).isInterface(); for (Iterator iter = c.getInterfaces().iterator(); iter.hasNext(); ) { addSupertypeMethods((ClassDefinition) iter.next(), methods, modMethods, seen); } if (isClazz && c.getSuperClass() != null) { // adds all superclass' abstract methods. addSupertypeMethods(c.getSuperClass(), methods, modMethods, seen); } for (Iterator iter = c.getContents().iterator(); iter.hasNext(); ) { Object obj = iter.next(); if (!(obj instanceof Method)) continue; Method m = (Method) obj; MethodKey key = new MethodKey(m); if (!isClazz || ((m.getModifiers() & Modifier.ABSTRACT) > 0)) { if (methods.containsKey(key)) { continue; } methods.put(key, m); modMethods.put(key, m); } else { // un-register the method: if (methods.remove(key) != null) { modMethods.remove(key); } } } } private Collection implementFromSuper(ClassElement target, Collection supertypes) { Map methods = new HashMap(31); Map modMethods = new HashMap(31); ClassDefinition cd = (ClassDefinition)((JMIElementCookie)target.getCookie(JMIElementCookie.class)).getElement(); JavaModelPackage pkg = (JavaModelPackage)cd.refOutermostPackage(); for (Iterator it = supertypes.iterator(); it.hasNext(); ) { Object obj = it.next(); JavaClass sjc = null; if (obj instanceof JavaClass) { sjc = (JavaClass) obj; } else { Identifier id = (Identifier)obj; sjc = resolve(id.getFullName(), pkg.getType(), pkg.getParameterizedType()); } if (sjc != null) { addSupertypeMethods(sjc, methods, modMethods, new HashSet(11)); } } Collection c = synchronizeMethods(cd, Collections.enumeration( methods.values()), Collections.enumeration(modMethods.values()), null, true); if (c == null || c.isEmpty()) return null; else return c; } protected byte getSynchronizationMode(ClassElement t) { return (byte)registrar.getSynchronizationMode(t); } protected void setSynchronizationMode(ClassElement t, byte value) { registrar.setSynchronizationMode(t, value); } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.