KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > JavaParserGlue


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.java;
21
22 import java.beans.*;
23 import java.io.*;
24 import java.util.*;
25 import java.lang.ref.Reference JavaDoc;
26 import java.lang.ref.WeakReference JavaDoc;
27
28 import javax.swing.event.ChangeListener JavaDoc;
29 import javax.swing.event.ChangeEvent JavaDoc;
30 import javax.swing.event.DocumentListener JavaDoc;
31 import javax.swing.text.BadLocationException JavaDoc;
32 import javax.swing.text.Segment JavaDoc;
33 import javax.swing.text.StyledDocument JavaDoc;
34
35 import org.openide.util.Task;
36 import org.openide.cookies.*;
37 import org.openide.loaders.MultiDataObject;
38 import org.openide.loaders.DataObject;
39 import org.openide.nodes.Node;
40 import org.openide.nodes.CookieSet;
41 import org.openide.src.*;
42 import org.openide.text.*;
43
44 import org.netbeans.modules.java.parser.LangEnvImpl;
45 import org.netbeans.modules.java.parser.JavaParser;
46 import org.netbeans.modules.java.codegen.DocumentBinding;
47 import org.netbeans.modules.java.codegen.TextBinding;
48
49 import org.netbeans.modules.java.bridge.BindingFactory;
50 import org.netbeans.modules.java.bridge.WrapperFactory;
51 import org.netbeans.modules.java.bridge.LangModel;
52 import org.netbeans.modules.java.bridge.ElementOrder;
53 import org.netbeans.modules.java.bridge.ElementImpl;
54
55 import org.netbeans.modules.java.parser.ParsingSupport;
56 import org.netbeans.modules.java.codegen.SourceText;
57 import org.netbeans.modules.java.bridge.DefaultLangModel;
58
59 import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
60
61
62
63 /**
64  * A glue between a JavaDataObject and JavaParser
65  *
66  * @author sdedic
67  * @version 0.1
68  */

69 class JavaParserGlue implements JavaParser.Env, DocumentBinding.Env,
70     LangModel.Env, SourceCookie.Editor {
71
72     private MultiDataObject.Entry sourceEntry;
73     private JavaDataObject jdo;
74     private DocumentBinding docBinding;
75     private LangEnvImpl envSupport;
76     private ParsingSupport parser;
77     private Map cookieMap;
78     private SiblingListener l;
79     private boolean documentLoaded;
80     private CloneableEditorSupport cloneableEditSupp;
81     private int suspended;
82     private PropertyChangeListener weakPropListener;
83     private boolean editorBound;
84     
85     /**
86      * Constructs an implementation of a parsing environment and binds it to the
87      * data object.
88      */

89     public JavaParserGlue(MultiDataObject.Entry en) {
90         this.sourceEntry = en;
91         this.jdo = (JavaDataObject)en.getDataObject();
92         this.docBinding = new SourceText(this);
93         this.envSupport = new LangEnvImpl(docBinding);
94         this.cookieMap = new WeakHashMap(57);
95         
96         DefaultLangModel model = new DefaultLangModel(this, jdo);
97         envSupport.setModel(model);
98         
99         parser = new ParsingSupport(this, jdo, docBinding, model, model);
100         l = new SiblingListener();
101         jdo.addPropertyChangeListener(l);
102     }
103     
104     /**
105      * The implementation provides custom OpenCookies that open the JavaEditor
106      * associated with the JavaDataObject at the where the Element starts.
107      */

108     public Node.Cookie findCookie(Element el, Class JavaDoc clazz) {
109         Node.Cookie lookup = null;
110
111         if (el == parser.getSource())
112             // handle it specially for SourceElement - it has much more common with DataObject than
113
// the rest of Elements.
114
return findCookie((SourceElement)el, clazz);
115         if (clazz == OpenCookie.class) {
116             lookup = lookupCookie(el, clazz);
117             if (lookup != null)
118                 return lookup;
119             lookup = createOpenCookie(el);
120         } else {
121             return jdo.getCookie(clazz);
122         }
123         return lookup;
124     }
125     
126     public void annotateThrowable(Throwable JavaDoc t, String JavaDoc locMessage, boolean user) {
127         Util.annotateThrowable(t, locMessage, user);
128     }
129     
130     public void annotateThrowable(Throwable JavaDoc wrapper, Throwable JavaDoc nested) {
131         Util.annotateThrowable(wrapper, nested);
132     }
133     
134     public Node.Cookie findCookie(SourceElement src, Class JavaDoc clazz) {
135         return jdo.getCookie(clazz);
136     }
137     
138     /**
139      * Notifies the mediator that a CloneablEditorSupport has been created.
140      */

141     public void cloneableSupportCreated(CloneableEditorSupport supp) {
142         bindEditorSupport(supp);
143     }
144     
145     public JavaParser getParser() {
146         return parser;
147     }
148
149     public org.openide.filesystems.FileObject getSourceFile() {
150         return jdo.getPrimaryFile();
151     }
152
153     public String JavaDoc getSourceName() {
154         return jdo.getPrimaryFile().getNameExt();
155     }
156
157     /**
158      * Environment can find precompiled classes to speed up name resoltion
159      */

160     public InputStream findCompiledClass(String JavaDoc classFQN) {
161         // PENDING: migrate code from the old V8ParseRequest
162
return null;
163     }
164     
165     /**
166      * The implementation first tries to get a document - if it is already opened.
167      * If it is, then it returns a CharArrayReader constructed on the document's
168      * contents. Document is read using {@link StyledDocument#render} to avoid
169      * data corruption.<P>
170      * If the document is not (yet) opened, a {@link JavaEditor#GuardedReader} is
171      * constructed so the output will not contain any guarded block information.
172      * <P>
173      * The implementation does not handle IOException from lower layers in any
174      * way and passes them to the caller.
175      */

176     public Reader getSourceText() throws IOException {
177         CloneableEditorSupport je = findEditorSupport();
178         final StyledDocument JavaDoc doc = je.getDocument();
179         
180         if (doc != null) {
181             // can read from the document!
182
final Segment JavaDoc s = new javax.swing.text.Segment JavaDoc();
183             doc.render(new Runnable JavaDoc() {
184                 public void run() {
185                     try {
186                         doc.getText(0, doc.getLength(), s);
187                     } catch (BadLocationException JavaDoc ex) {
188                         // should never happen
189
}
190                 }
191             });
192             return new CharArrayReader(s.array, s.offset, s.count);
193         } else {
194             JavaDataLoader.JavaFileEntry en = (JavaDataLoader.JavaFileEntry)sourceEntry;
195             return new JavaEditor.GuardedReader(en.getInputStream(), true,
196                 Util.getFileEncoding(en.getFile()));
197         }
198     }
199         
200     /**
201      * Creates an OpenCookie for the specified element. The cookies created are
202      * kept in caching WeakHashMap keyed by the element instances for reuse.
203      */

204     protected OpenCookie createOpenCookie(Element el) {
205         ElementImpl impl = (ElementImpl)el.getCookie(ElementImpl.class);
206         OpenCookie ck = new OpenCookieImpl((TextBinding)impl.getBinding());
207         return ck;
208     }
209     
210     private Node.Cookie lookupCookie(Element el, Class JavaDoc clazz) {
211         synchronized (cookieMap) {
212             Object JavaDoc o = cookieMap.get(el);
213             if (o == null)
214                 return null;
215             
216             if (o instanceof CookieSet)
217                 return ((CookieSet)o).getCookie(clazz);
218             
219             if (o.getClass().isAssignableFrom(clazz))
220                 return (Node.Cookie)o;
221             return null;
222         }
223     }
224     
225     private TextBinding getBinding(Element el) {
226         ElementImpl impl = (ElementImpl)el.getCookie(ElementImpl.class);
227         if (impl == null) {
228             Element.Impl iimpl = (Element.Impl)el.getCookie(Element.Impl.class);
229             throw new IllegalArgumentException JavaDoc("Incompatible implementation: " + // NOI18N
230
iimpl);
231         }
232         return (TextBinding)impl.getBinding();
233     }
234
235
236     // ============== Implementation of DocumentBinding.Env ==================
237

238     public CloneableEditorSupport findEditorSupport() {
239         if (this.cloneableEditSupp == null) {
240             bindEditorSupport(jdo.findCloneableEditorSupport());
241         }
242         return cloneableEditSupp;
243     }
244     
245     public void takeLock() throws IOException {
246         jdo.getPrimaryEntry().takeLock();
247     }
248
249     private synchronized void bindEditorSupport(CloneableEditorSupport supp) {
250         if (!editorBound) {
251             supp.addChangeListener(l);
252             documentLoaded = supp.isDocumentLoaded();
253             editorBound = true;
254             cloneableEditSupp = supp;
255             if (documentLoaded)
256                 l.stateChanged(new ChangeEvent JavaDoc(supp));
257         }
258     }
259     
260     public PositionRef findFreePosition(PositionBounds bounds) {
261         return getJavaEditor().findFreePosition(bounds);
262     }
263     
264     private JavaEditor getJavaEditor() {
265         return (JavaEditor)jdo.getCookie(JavaEditor.class);
266     }
267
268     // ============== Implementation of LangModel.Env -- DELEGATING ==================
269
/**
270      * Returns the document binding as the binding factory.
271      */

272     public BindingFactory getBindingFactory() {
273         return envSupport.getBindingFactory();
274     }
275
276     public WrapperFactory getWrapperFactory() {
277         return envSupport.getWrapperFactory();
278     }
279
280     public void complete(Element scope, int informationKind) {
281         envSupport.complete(scope, informationKind);
282     }
283     
284     public Type resolveType(Element context, Type original) {
285         return envSupport.resolveType(context, original);
286     }
287     
288     public Identifier resolveTypeIdent(Element context, Identifier original) {
289         return envSupport.resolveTypeIdent(context, original);
290     }
291     
292     /**
293      * Implementation of SourceCookie.
294      */

295     public SourceElement getSource() {
296         return parser.getSource();
297     }
298     
299     /**
300      * Implementation of OpenCookie available on individual elements.
301      */

302     private class OpenCookieImpl implements OpenCookie, Runnable JavaDoc {
303         TextBinding binding;
304         
305         OpenCookieImpl(TextBinding binding) {
306             this.binding = binding;
307         }
308         
309         public void open() {
310             // Fix #20551: if the thread is not the event one, replan
311
// the open action into the AWT thread.
312
org.openide.util.Mutex.EVENT.postReadRequest(this);
313         }
314         
315         public void run() {
316             PositionBounds elBounds = binding.getElementRange(true);
317             getJavaEditor().openAt(elBounds.getBegin());
318         }
319     }
320     
321     public StyledDocument JavaDoc getDocument() {
322         return findEditorSupport().getDocument();
323     }
324     
325     public Line.Set getLineSet() {
326         return findEditorSupport().getLineSet();
327     }
328     
329     public javax.swing.JEditorPane JavaDoc[] getOpenedPanes() {
330         return findEditorSupport().getOpenedPanes();
331     }
332     
333     public boolean isModified() {
334         return findEditorSupport().isModified();
335     }
336     
337     public void open() {
338         findEditorSupport().open();
339     }
340     
341     public StyledDocument JavaDoc openDocument() throws IOException {
342         return findEditorSupport().openDocument();
343     }
344     
345     public Task prepareDocument() {
346         return findEditorSupport().prepareDocument();
347     }
348     
349     public void saveDocument() throws IOException {
350         findEditorSupport().saveDocument();
351     }
352     
353     public boolean close() {
354         return findEditorSupport().close();
355     }
356     
357     public void suspendDocumentChanges() {
358         suspended++;
359     }
360     
361     public void resumeDocumentChanges() {
362         --suspended;
363     }
364     
365     protected boolean isDocumentSuspended() {
366         return suspended > 0;
367     }
368     
369     private void dissolve() {
370         suspendDocumentChanges();
371         jdo.removePropertyChangeListener(l);
372         // callback to JavaDataObject (disable rest of the system).
373
jdo.suspendSupports();
374
375         synchronized (this) {
376             if (cloneableEditSupp != null) {
377                 cloneableEditSupp.removeChangeListener(l);
378                 editorBound = false;
379                 StyledDocument JavaDoc d = cloneableEditSupp.getDocument();
380                 if (d != null)
381                     d.removeDocumentListener(l);
382             }
383         }
384         parser.invalidate();
385     }
386     
387     private class SiblingListener implements PropertyChangeListener, ChangeListener JavaDoc,
388         DocumentListener JavaDoc {
389         
390         private StyledDocument JavaDoc doc;
391         
392         public void propertyChange(PropertyChangeEvent p) {
393             String JavaDoc evName = p.getPropertyName();
394             Object JavaDoc source = p.getSource();
395             
396             if (source == jdo)
397                 dataObjectPropertyChange(evName, p);
398         }
399         
400         private void dataObjectPropertyChange(String JavaDoc evName, final PropertyChangeEvent p) {
401             if (DataObject.PROP_VALID.equals(evName) && ((Boolean JavaDoc)p.getNewValue()).booleanValue() == false) {
402                 dissolve();
403             }
404         }
405         
406         public void stateChanged(ChangeEvent JavaDoc e) { // document state change
407
CloneableEditorSupport supp = (CloneableEditorSupport)e.getSource();
408             StyledDocument JavaDoc d = supp.getDocument();
409             
410             if (d != null) {
411                 if (doc == null) {
412                     synchronized (this) {
413                         doc = d;
414                         d.addDocumentListener(this);
415                         documentLoaded = true;
416                     }
417                 }
418             } else {
419                 removeDocListener();
420             }
421         }
422         
423         private synchronized void removeDocListener() {
424             if (doc != null)
425                 doc.removeDocumentListener(this);
426             doc = null;
427             documentLoaded = false;
428         }
429         
430         public void removeUpdate(javax.swing.event.DocumentEvent JavaDoc p1) {
431             documentChanged();
432         }
433         
434         public void changedUpdate(javax.swing.event.DocumentEvent JavaDoc p1) {
435             // text is not modified, so we can ignore this event
436
}
437         
438         public void insertUpdate(javax.swing.event.DocumentEvent JavaDoc p1) {
439             documentChanged();
440         }
441         
442         private void documentChanged() {
443             if (!isDocumentSuspended()) {
444                 parser.sourceChanged(-1, -1);
445                 JavaMetamodel.getManager().addModified(jdo.getPrimaryFile());
446                 getJavaEditor().restartTimer(false);
447             }
448         }
449     }
450     
451     private Map swingElementMap;
452     
453     // SourceCookie.Editor - specifics
454
public org.openide.src.Element findElement(int offset) {
455         javax.swing.text.Element JavaDoc swingEl = sourceToText(getSource());
456         
457         while (swingEl != null) {
458             if (swingEl.isLeaf()) {
459                 return ((TextElement)swingEl).getSourceElement();
460             }
461             int elIndex = swingEl.getElementIndex(offset);
462             if (elIndex == -1)
463                 return ((TextElement)swingEl).getSourceElement();
464             swingEl = swingEl.getElement(elIndex);
465         }
466         return null;
467
468     }
469     
470     public org.openide.src.Element textToSource(javax.swing.text.Element JavaDoc element) throws NoSuchElementException {
471         if (!(element instanceof TextElement)) {
472             throw new NoSuchElementException();
473         }
474         TextElement el = (TextElement)element;
475         return el.getSourceElement();
476     }
477
478     /**
479      * Returns null, if the underlying document has not yet been loaded
480      */

481     public javax.swing.text.Element JavaDoc sourceToText(org.openide.src.Element element) {
482         javax.swing.text.Document JavaDoc d;
483         try {
484             d = findEditorSupport().openDocument();
485         } catch (IOException ex) {
486             IllegalStateException JavaDoc x = new IllegalStateException JavaDoc("Could not load document"); // NOI18N
487
org.openide.ErrorManager.getDefault().annotate(x, ex);
488             throw x;
489         }
490         if (swingElementMap == null) {
491             synchronized (this) {
492                 if (swingElementMap == null)
493                     swingElementMap = new WeakHashMap(75);
494             }
495         }
496        Reference JavaDoc r = (Reference JavaDoc)swingElementMap.get(element);
497         javax.swing.text.Element JavaDoc e = r == null ? null : (javax.swing.text.Element JavaDoc)r.get();
498         if (e == null) {
499             e = new TextElement(element);
500             synchronized (this) {
501                 swingElementMap.put(element, new WeakReference JavaDoc(e));
502             }
503         }
504         return e;
505     }
506     
507     private static final Element[] NO_CHILDREN = new Element[0];
508     
509     private class TextElement implements TextBinding.ExElement {
510         private Element myElement;
511         private org.netbeans.jmi.javamodel.Element refObject;
512         
513         public TextElement(Element element) {
514             myElement = element;
515             ElementImpl impl = (ElementImpl) myElement.getCookie(ElementImpl.class);
516             if (impl != null) {
517                 refObject = (org.netbeans.jmi.javamodel.Element)impl.getJavaElement ();
518             }
519         }
520         
521         private PositionBounds getBounds() {
522             try {
523                 JavaMetamodel manager=JavaMetamodel.getManager();
524                 return manager.getElementPosition(refObject, true);
525             } catch (javax.jmi.reflect.InvalidObjectException e) {
526                 return null;
527             }
528         }
529         
530         public PositionRef getDeclarationStart() {
531             try {
532                 PositionBounds bounds = JavaMetamodel.getManager().getElementPosition(refObject);
533                 if (bounds == null)
534                     return null;
535                 return bounds.getBegin ();
536             } catch (javax.jmi.reflect.InvalidObjectException e) {
537                 return null;
538             }
539         }
540         
541         private Element[] getChildrenElements() {
542             ElementOrder ck = (ElementOrder)myElement.getCookie(
543                 ElementOrder.class);
544             if (ck == null)
545                 return NO_CHILDREN;
546             return ck.getElements();
547         }
548         
549         public int getElementIndex(int offset) {
550             Element[] children = getChildrenElements();
551             javax.swing.text.Element JavaDoc childElement;
552             
553             for (int i = 0; i < children.length; i++) {
554                 childElement = sourceToText(children[i]);
555                 if (childElement.getStartOffset() <= offset &&
556                     childElement.getEndOffset() >= offset) {
557                     return i;
558                 }
559             }
560             return -1;
561         }
562         
563         public javax.swing.text.AttributeSet JavaDoc getAttributes() {
564             return null;
565         }
566         
567         public Element getSourceElement() {
568             return myElement;
569         }
570         
571         public javax.swing.text.Document JavaDoc getDocument() {
572             return JavaParserGlue.this.getDocument();
573         }
574         
575         public javax.swing.text.Element JavaDoc getElement(int index) {
576             Element[] els = getChildrenElements();
577             if (index > els.length)
578                 throw new IllegalArgumentException JavaDoc();
579             return sourceToText(els[index]);
580         }
581         
582         public int getElementCount() {
583             return getChildrenElements().length;
584         }
585         
586         public int getEndOffset() {
587             PositionBounds bounds = getBounds();
588             return bounds != null ? getBounds().getEnd().getOffset() - 1 : 0; // [PENDING]
589
}
590         
591         public String JavaDoc getName() {
592             return myElement.getClass().getName();
593         }
594         
595         public javax.swing.text.Element JavaDoc getParentElement() {
596             Element parent;
597
598             if (myElement instanceof MemberElement) {
599                 parent = ((MemberElement)myElement).getDeclaringClass();
600                 if (parent == null && myElement instanceof ClassElement) {
601                     parent = ((ClassElement)myElement).getSource();
602                 }
603             } else if (myElement instanceof InitializerElement) {
604                 parent = ((InitializerElement)myElement).getDeclaringClass();
605             } else
606                 return null;
607             return sourceToText(parent);
608         }
609         
610         public int getStartOffset() {
611             PositionBounds bounds = getBounds();
612             return bounds != null ? bounds.getBegin().getOffset() : 0;
613         }
614         
615         public boolean isLeaf() {
616             return getChildrenElements().length == 0;
617         }
618     }
619 }
620
Popular Tags