KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > ui > nodes > elements > ChildrenProvider


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 package org.netbeans.modules.java.ui.nodes.elements;
20
21 import org.openide.nodes.Node;
22 import org.openide.nodes.Children;
23 import org.openide.util.RequestProcessor;
24 import org.openide.util.Mutex;
25 import org.openide.ErrorManager;
26 import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
27 import org.netbeans.modules.javacore.JMManager;
28 import org.netbeans.jmi.javamodel.Element;
29
30 import javax.jmi.reflect.JmiException;
31 import javax.jmi.reflect.InvalidObjectException;
32 import java.util.*;
33
34 /**
35  * provides children (jmi elements and their nodes) in async way. It should
36  * be used if you cannot create keys and nodes in the AWT event queue.
37  */

38 final class ChildrenProvider implements Runnable JavaDoc {
39         
40     /**
41      * computes elements (children), creates their nodes, presents them.
42      */

43     interface KeyHandler {
44         /**
45          * subclasses implement this to supply child keys
46          * @return keys
47          */

48         List collectKeys();
49         
50         /**
51          * creates nodes for a given key. The method is invoked inside
52          * Children.MUTEX and MDR transaction.
53          * @param key the key
54          * @return child nodes for this key or null if there should be no
55          * nodes for this key
56          */

57         Node[] prepareNodes(Object JavaDoc key);
58         
59         /**
60          * subclasses implement this to add nodes to Children.
61          * Children.Key.setKeys() will be most often implementation.
62          * @param keys child keys
63          * @param nodes list of nodes corresponding to keys
64          */

65         void presentKeys(List/*<Element>*/ keys, List/*<Node[]>*/ nodes);
66     }
67         
68     /**
69      * processor computing keys and their nodes to not block
70      * the awt event queue
71      */

72     static final RequestProcessor RP = new RequestProcessor("Java Children Provider"); // NOI18N
73

74     private RequestProcessor.Task currentTask;
75         
76     private Map/*<Element, Node[]>*/ nodes = initNodeMap();
77     
78     /** keys */
79     private List elements;
80         
81     private final KeyHandler keyHandler;
82
83     public ChildrenProvider(KeyHandler keyHandler) {
84         this.keyHandler = keyHandler;
85     }
86
87     public void run() {
88         JMManager.getTransactionMutex().addPriorityThread();
89         List/*<Element*/ keys;
90         Map/*<Element, Node[]>*/ nodesNew;
91         try {
92             keys = keyHandler.collectKeys();
93             nodesNew = createNodeMap(nodes, keys);
94         } catch (InvalidObjectException e) {
95             // some element is invalid. MDR will notify listeners about that change later
96
keys = Collections.EMPTY_LIST;
97             nodesNew = Collections.EMPTY_MAP;
98         } catch (JmiException e) {
99             keys = Collections.EMPTY_LIST;
100             nodesNew = Collections.EMPTY_MAP;
101             ErrorManager.getDefault().notify(ErrorManager.WARNING, e);
102         }
103
104         synchronized(this) {
105             elements = keys;
106             nodes = nodesNew;
107         }
108         presentKeys(keys, nodesNew);
109     }
110
111     private void presentKeys(final List keys, final Map nodesNew) {
112         List nodes = new ArrayList(keys.size());
113         for (Iterator it = keys.iterator(); it.hasNext();) {
114             Object JavaDoc key = it.next();
115             Node[] ns = (Node[]) nodesNew.get(key);
116             nodes.add(ns);
117             
118         }
119         keyHandler.presentKeys(keys, nodes);
120     }
121
122     private Map/*<Element, Node[]>*/ initNodeMap() {
123         Map/*<Element, Node[]>*/ nodesNew = new WeakHashMap/*<Element, Node[]>*/();
124         return nodesNew;
125     }
126         
127     /**
128      * non-blocking operation that recomputes keys and update their nodes
129      */

130     public synchronized void recomputeChildren() {
131         if (currentTask == null) {
132             currentTask = RP.post(this);
133         } else {
134             currentTask.schedule(0);
135         }
136     }
137     
138     /**
139      * gets node for element. It is a non-blocking operation
140      * @param element element as a key
141      * @return node or <code>null</null> if the node has not been created yet
142      */

143     public Node getNode(Object JavaDoc element) {
144         Node[] ns = null;
145         synchronized (this) {
146             ns = (Node[]) nodes.get(element);
147         }
148         return ns == null? null: ns[0];
149     }
150     
151     /**
152      * gets keys; blocking opreration
153      * @return keys
154      */

155     public Collection getKeys() {
156         computeChildren();
157         synchronized (this) {
158             return elements;
159         }
160     }
161     
162     /**
163      * waits untill the keys and nodes are ready.
164      */

165     public void waitFinished() {
166         computeChildren();
167     }
168     
169     /**
170      * stops the running task and sets children as empty collection
171      */

172     public void clear() {
173         RP.post(new CleanTask());
174     }
175     
176     private void clearImpl() {
177         synchronized (this) {
178             elements = Collections.EMPTY_LIST;
179             nodes = Collections.EMPTY_MAP;
180         }
181         presentKeys(elements, nodes);
182     }
183         
184     private void computeChildren() {
185         synchronized (this) {
186             if (currentTask == null) {
187                 recomputeChildren();
188             }
189         }
190         currentTask.waitFinished();
191     }
192     
193     private Map/*<Element, Node[]>*/ createNodeMap(
194             final Map/*<Element, Node[]>*/ nodes, final List keys) throws JmiException {
195         final Map/*<Element, Node[]>*/ nodesNew = initNodeMap();
196         if (keys.isEmpty()) {
197             return nodesNew;
198         }
199         
200         JmiException ex = (JmiException) Children.MUTEX.readAccess(new Mutex.Action() {
201             public Object JavaDoc run() {
202                 try {
203                     JMManager.getTransactionMutex().addPriorityThread();
204                     JavaMetamodel.getDefaultRepository().beginTrans(false);
205                     try {
206                         for (Iterator it = keys.iterator(); it.hasNext();) {
207                             Object JavaDoc key = it.next();
208                             if (key instanceof Element && !((Element) key).isValid()) {
209                                 // some element is invalid. MDR will notify listeners about that change later
210
// throw out the map
211
nodesNew.clear();
212                                 keys.clear();
213                                 return null;
214                             } else {
215                                 Node[] ns = (Node[]) nodes.get(key);
216                                 if (ns == null) {
217                                     ns = keyHandler.prepareNodes(key);
218                                 }
219                                 nodesNew.put(key, ns);
220                             }
221                         }
222                     } finally {
223                         JavaMetamodel.getDefaultRepository().endTrans();
224                     }
225                 } catch (JmiException ex) {
226                     return ex;
227                 }
228                 return null;
229             }
230
231         });
232         
233         if (ex != null) {
234             throw ex;
235         }
236         return nodesNew;
237     }
238     
239     private final class CleanTask implements Runnable JavaDoc {
240         
241         public void run() {
242             clearImpl();
243         }
244
245     }
246         
247 }
248
Popular Tags