|
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; import java.lang.reflect.Modifier; import java.util.*; import javax.swing.SwingUtilities; import javax.swing.text.StyledDocument; import javax.jmi.reflect.InvalidObjectException; import org.netbeans.api.mdr.MDRObject; import org.netbeans.api.mdr.events.AttributeEvent; import org.netbeans.api.mdr.events.MDRChangeEvent; import org.netbeans.api.mdr.events.MDRChangeListener; import org.netbeans.jmi.javamodel.*; import org.netbeans.modules.java.settings.JavaSettings; import org.netbeans.modules.javacore.internalapi.JavaMetamodel; import org.netbeans.modules.javacore.JMManager; import org.openide.ErrorManager; import org.openide.cookies.LineCookie; import org.openide.text.Annotation; import org.openide.text.Line; import org.openide.util.RequestProcessor; /** * The main purpose of this class is to manage annotations of overridden and implemented methods for a particular * JavaEditor. Unused instances should release resources by {@link #suspend}. The suspended instance should not be * reused. * * @author Jan Pokorsky, Tomas Zezula */ final class OverrideAnnotationSupport { private final JavaEditor editor; private WMDRChangeListener overriddenListener; private Request currentRequest; /* List of override attached to this document */ private List overrideAnnotations = new ArrayList (); /** model was cleared so do not try to do anything with it */ private boolean isSuspended = false; private static final RequestProcessor QUEUE = new RequestProcessor("Overriddens Queue", 1); // NOI18N public OverrideAnnotationSupport(JavaEditor editor) { this.editor = editor; this.overriddenListener = new WMDRChangeListener(this); } /** computes annotations and attaches them. */ public void processOverriddenAnnotation() { if (!isEnabled()) return; synchronized(this) { if (isSuspended) return; if (currentRequest != null && !currentRequest.cancel()) { currentRequest.followMe = true; return; } currentRequest = new Request(); // schedule the request with a delay to prevent excessive cpu consumption in case of flood of requests QUEUE.post(currentRequest, 200); } } /** stops processing, unregisters listeners, detaches annotations */ public void suspend() { // boolean isRunning = false; synchronized(this) { if (this.isSuspended) return; this.isSuspended = true; if (this.currentRequest != null && !this.currentRequest.cancel()) { // isRunning = true; this.currentRequest.followMe = false; } } Request clean = new Request(Request.CLEAN); // if (isRunning) { // do not block // MaM - isRunning commented out to always perform this in the QUEUE to prevent deadlocks (#46115) QUEUE.post(clean); // } else { // clean.run(); // } } private void dispose() { if (this.overriddenListener != null) { this.overriddenListener.removeAllElements(); } detachAnnotations(this.overrideAnnotations); this.overrideAnnotations.clear(); } /** show annotations? */ private boolean isEnabled() { return JavaSettings.getDefault().getShowOverriding(); } private void processOverriddenAnnotation (Resource rsc) { // System.err.println("### DO RECOMPUTE OVERRIDENS: " + editor.getDataObject().getPrimaryFile() + ", " + Thread.currentThread()); if (JMManager.PERF_DEBUG) Thread.dumpStack(); final List originalAnnotations = copyAnnotations(); final List overrideAnnotations = this.findOverriddenMethods(rsc); final List addedOverrideAnnotations = new ArrayList (overrideAnnotations); addedOverrideAnnotations.removeAll (originalAnnotations); final List removedOverrideAnnotations = new ArrayList (originalAnnotations); removedOverrideAnnotations.removeAll (overrideAnnotations); final List unchangedOverrideAnnotations = new ArrayList (originalAnnotations); unchangedOverrideAnnotations.retainAll (overrideAnnotations); if (isSuspended) return; detachAnnotations (removedOverrideAnnotations); if (editor.isDocumentLoaded() && !addedOverrideAnnotations.isEmpty()) { StyledDocument doc = editor.getDocument(); Runnable docRenderer = new Runnable() { public void run() { LineCookie cookie = (LineCookie) editor.getDataObject().getCookie(LineCookie.class); Line.Set lines = cookie.getLineSet(); for (Iterator it = addedOverrideAnnotations.iterator(); it.hasNext();) { OverrideAnnotation ann = (OverrideAnnotation) it.next (); ann.attachToLineSet (lines); } } }; if (doc != null) { JavaMetamodel.getDefaultRepository().beginTrans(false); try { doc.render(docRenderer); } finally { JavaMetamodel.getDefaultRepository().endTrans(); } } else { SwingUtilities.invokeLater (docRenderer); } } List computedAnnotations = unchangedOverrideAnnotations; computedAnnotations.addAll(addedOverrideAnnotations); syncAnnotations(computedAnnotations); } private synchronized List copyAnnotations() { return new ArrayList(this.overrideAnnotations); } private synchronized void syncAnnotations(List l) { this.overrideAnnotations = l; } private void processOverriddenAnnotationImpl() { Resource rsc = editor.getResource(); if (rsc != null) { processOverriddenAnnotation(rsc); } } private List findOverriddenMethods(JavaClass cls, Map methods) { if (methods.isEmpty()) return Collections.EMPTY_LIST; JavaClass parent; List result = new ArrayList (); List interfaces = new ArrayList (); interfaces.addAll(cls.getInterfaces()); parent = cls.getSuperClass(); while (parent != null) { if (isSuspended) return Collections.EMPTY_LIST; if (Modifier.isFinal (parent.getModifiers())) { break; } if (findOverridenMethods(parent, interfaces, methods, result)) return result; cls = parent; parent = cls.getSuperClass(); } Set visited = new HashSet(); while (!interfaces.isEmpty()) { JavaClass ifc = (JavaClass) interfaces.remove(0); if (visited.add(ifc)) { if (findOverridenMethods(ifc, interfaces, methods, result)) return result; } } return result; } private boolean findOverridenMethods(JavaClass parent, List interfaces, Map methods, List result) { this.overriddenListener.addElement(parent); interfaces.addAll(parent.getInterfaces()); for (Iterator it = parent.getContents().iterator(); it.hasNext();) { ClassMember tmp = (ClassMember) it.next(); if (tmp instanceof Method) { int modifiers = tmp.getModifiers(); if (!Modifier.isStatic(modifiers) && !Modifier.isFinal(modifiers) && !Modifier.isPrivate(modifiers)) { Method m = (Method) methods.get(tmp); if (m != null) { methods.remove (m); result.add (new OverrideAnnotation.Descriptor((Method) tmp,m)); if (methods.isEmpty()) { //Fully covered return true; } } } } } return false; } private Map createMethodMap (JavaClass cls, Set classes) { Map methods = new TreeMap (new Comparator() { public int compare(Object o1, Object o2) { Method m1 = (Method) o1, m2 = (Method) o2; int result = m1.getName() == null ? -1 : m1.getName().compareTo(m2.getName()); if (result == 0) { List p1 = m1.getParameters(), p2 = m2.getParameters(); Iterator it2 = p2.iterator(); for (Iterator it1 = p1.iterator(); it1.hasNext() && result == 0;) { Type param1 = ((Parameter) it1.next()).getType(); if (it2.hasNext()) { Type param2 = ((Parameter) it2.next()).getType(); result = param1 == null || param1.getName() == null ? -1 : (param2 == null ? 1 : param1.getName().compareTo(param2.getName())); } else { result = -1; } } if (result == 0 && it2.hasNext()) { result = 1; } } if (result == 0) { result = m1.getType() == null || m1.getType().getName() == null ? -1 : (m2.getType() == null ? 1 : m1.getType().getName().compareTo(m2.getType().getName())); } return result; } }); for (Iterator it = cls.getContents().iterator(); it.hasNext();) { ClassMember tmp = (ClassMember) it.next(); if (tmp instanceof Method) { int modifiers = tmp.getModifiers(); if (!Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers)) { methods.put (tmp, tmp); } } else if (tmp instanceof JavaClass) { classes.add(tmp); } } return methods; } private List findOverriddenMethods (Resource rsc) { JavaMetamodel.getDefaultRepository().beginTrans(false); try { JavaMetamodel.getManager().setClassPath(rsc); Set classes = new HashSet(rsc.getClassifiers()); List result = new ArrayList (); while (!classes.isEmpty()) { Iterator tmp = classes.iterator(); JavaClass cls = (JavaClass) tmp.next(); tmp.remove(); this.overriddenListener.addElement(cls); List methodsDescriptor = findOverriddenMethods(cls, createMethodMap(cls, classes)); if (isSuspended) return result; for (Iterator it = methodsDescriptor.iterator(); it.hasNext();) { OverrideAnnotation.Descriptor descriptor = (OverrideAnnotation.Descriptor) it.next (); result.add (OverrideAnnotation.forDescriptor (descriptor)); } } return result; } catch (InvalidObjectException e) { // ignore return Collections.EMPTY_LIST; } finally { JavaMetamodel.getDefaultRepository().endTrans(); } } private static void detachAnnotations(Collection anns) { for (Iterator i = anns.iterator(); i.hasNext();) { Annotation ann = (Annotation) i.next(); try { ann.detach(); } catch (Exception e) { ErrorManager.getDefault().notify(ErrorManager.WARNING, e); } } } /** represents sheduled reqest to process overridden annotations */ private class Request implements Runnable { private boolean isCanceled = false; private boolean isRunning = false; /** follow current reqest with a new one when it is finished */ private boolean followMe = false; /** request type */ private final int type; private static final int DEFAULT = 0; private static final int CLEAN = 1; public Request() { this(DEFAULT); } public Request(int type) { this.type = type; } public void run() { switch (type) { case DEFAULT: computeAnnotations(); break; case CLEAN: dispose(); break; default: assert false: "Invalid request type: " + type; // NOI18N } } private void computeAnnotations() { if (isCanceled) return; try { isRunning = true; processOverriddenAnnotationImpl(); } finally { isRunning = false; } synchronized(OverrideAnnotationSupport.this) { if (followMe) { followMe = false; processOverriddenAnnotation(); } } } /** * @return true if canceled */ public boolean cancel() { isCanceled = true; return !isRunning; } } /** listens to changes of class, superclasses, interfaces and all their methods */ private static class WMDRChangeListener implements MDRChangeListener { OverrideAnnotationSupport support; //Map |
... 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.