KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openidex > search > DataObjectSearchGroup


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
21 package org.openidex.search;
22
23
24 import java.io.IOException JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Arrays JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.Enumeration JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Set JavaDoc;
33 import org.openide.ErrorManager;
34
35 import org.openide.cookies.InstanceCookie;
36 import org.openide.filesystems.FileSystem;
37 import org.openide.filesystems.Repository;
38 import org.openide.loaders.DataObject;
39 import org.openide.util.Lookup;
40 import org.openide.util.NbBundle;
41 import org.openide.nodes.Node;
42
43 //import org.netbeans.api.project.FileOwnerQuery;
44

45
46 /**
47  * Search group which perform search on data objects. It is a
48  * convenience and the default implementation of <code>SearchGroup</code>
49  * abstract class.
50  *
51  * @author Peter Zavadsky
52  * @author Marian Petras
53  * @see org.openidex.search.SearchGroup
54  */

55 public class DataObjectSearchGroup extends SearchGroup {
56
57     
58     /**
59      * {@inheritDoc} If the specified search type does not support searching
60      * in <code>DataObject</code>s, the group is left unmodified, too.
61      *
62      * @see SearchType#getSearchTypeClasses()
63      */

64     protected void add(SearchType searchType) {
65         boolean ok = false;
66         Class JavaDoc[] classes = searchType.getSearchTypeClasses();
67         for (int i = 0; i < classes.length; i++) {
68             if (classes[i] == DataObject.class) {
69                 ok = true;
70                 break;
71             }
72         }
73         if (ok) {
74             super.add(searchType);
75         }
76     }
77
78     /**
79      * Actual search implementation. Fires PROP_FOUND notifications.
80      * Implements superclass abstract method.
81      *
82      * @throws RuntimeException annotated at USER level by reason (on low memory condition)
83      */

84     public void doSearch() {
85         Node[] nodes = normalizeNodes(
86                 (Node[]) searchRoots.toArray(new Node[searchRoots.size()]));
87
88         lowMemoryWarning = false;
89         lowMemoryWarningCount = 0;
90         assureMemory(REQUIRED_PER_ITERATION, true);
91
92         for (int i = 0; i < nodes.length; i++) {
93             Node node = nodes[i];
94             SearchInfo info = Utils.getSearchInfo(node);
95             if (info != null) {
96                 for (Iterator JavaDoc j = info.objectsToSearch(); j.hasNext(); ) {
97                     if (stopped) return;
98                     assureMemory(REQUIRED_PER_ITERATION, false);
99                     processSearchObject(/*DataObject*/ j.next());
100                 }
101             }
102         }
103     }
104
105
106     private static boolean lowMemoryWarning = false;
107     private static int lowMemoryWarningCount = 0;
108     private static int MB = 1024 * 1024;
109     private static int REQUIRED_PER_ITERATION = 2 * MB;
110     private static int REQUIRED_PER_FULL_GC = 7 * MB;
111
112     /**
113      * throws RuntimeException if low memory condition happens
114      * @param estimate etimated memory requirements before next check
115      * @param tryGC on true use potentionally very slow test that is more accurate (cooperates with GC)
116      */

117     private static void assureMemory(int estimate, boolean tryGC) {
118         Runtime JavaDoc rt = Runtime.getRuntime();
119         long total = rt.totalMemory();
120         long max = rt.maxMemory(); // XXX on some 1.4.1 returns heap&native instead of -Xmx
121
long required = Math.max(total/13, estimate + REQUIRED_PER_FULL_GC);
122         if (total == max && rt.freeMemory() < required) {
123             // System.err.println("MEM " + max + " " + total + " " + rt.freeMemory());
124
if (tryGC) {
125                 try {
126                     byte[] gcProvocation = new byte[(int)required];
127                     gcProvocation[0] = 75;
128                     gcProvocation = null;
129                     return;
130                 } catch (OutOfMemoryError JavaDoc e) {
131                     throwNoMemory();
132                 }
133             } else {
134                 lowMemoryWarning = true;
135             }
136         } else if (lowMemoryWarning) {
137             lowMemoryWarning = false;
138             lowMemoryWarningCount ++;
139         }
140         // gc is getting into corner
141
if (lowMemoryWarningCount > 7 || (total == max && rt.freeMemory() < REQUIRED_PER_FULL_GC)) {
142             throwNoMemory();
143         }
144
145     }
146
147     private static void throwNoMemory() {
148         RuntimeException JavaDoc ex = new RuntimeException JavaDoc("Low memory condition"); // NOI18N
149
String JavaDoc msg = NbBundle.getMessage(DataObjectSearchGroup.class, "EX_memory");
150         ErrorManager.getDefault().annotate(ex, ErrorManager.USER, null, msg, null, null);
151         throw ex;
152     }
153
154 // /**
155
// * Gets data folder roots on which to search.
156
// *
157
// * @return array of data folder roots
158
// */
159
// private DataObject.Container[] getContainers() {
160
// List children = null;
161
// Node[] nodes = normalizeNodes(
162
// (Node[]) searchRoots.toArray(new Node[searchRoots.size()]));
163
//
164
// for (int i = 0; i < nodes.length; i++) {
165
// Node node = nodes[i];
166
// if (node.getParentNode() == null) {
167
//
168
// /* it should be the root of some project */
169
// }
170
// }
171
//
172
// /* test whether to scan whole repository: */
173
// if (nodes.length == 1) {
174
// InstanceCookie ic = (InstanceCookie) nodes[0].getCookie(
175
// InstanceCookie.class);
176
// try {
177
// if (ic != null && Repository.class
178
// .isAssignableFrom(ic.instanceClass())) {
179
//
180
// /* yes - scanning whole repository: */
181
// children = new ArrayList(10);
182
// Enumeration fss = Repository.getDefault().getFileSystems();
183
// while (fss.hasMoreElements()) {
184
// FileSystem fs = (FileSystem) fss.nextElement();
185
// if (fs.isValid() && !fs.isHidden()) {
186
// children.add(DataObject.find(fs.getRoot()));
187
// }
188
// }
189
// }
190
// } catch (IOException ioe) {
191
// ErrorManager.getDefault().notify(ErrorManager.EXCEPTION, ioe);
192
// children = null;
193
// } catch (ClassNotFoundException cnfe) {
194
// ErrorManager.getDefault().notify(ErrorManager.EXCEPTION, cnfe);
195
// children = null;
196
// }
197
// }
198
// if (children == null) {
199
// children = new ArrayList(nodes.length);
200
// for (int i = 0; i < nodes.length; i++) {
201
// DataObject.Container container = (DataObject.Container)
202
// nodes[i].getCookie(DataObject.Container.class);
203
// if (container != null) {
204
// children.add(container);
205
// }
206
// }
207
// }
208
// return (DataObject.Container[])
209
// children.toArray(new DataObject.Container[children.size()]);
210
// }
211
//
212
// /**
213
// * Scans data folder recursively.
214
// *
215
// * @return <code>true</code> if scanned entire folder successfully
216
// * or <code>false</code> if scanning was stopped. */
217
// private boolean scanContainer(DataObject.Container container) {
218
// DataObject[] children = container.getChildren();
219
//
220
// for (int i = 0; i < children.length; i++) {
221
//
222
// /* Test if the search was stopped. */
223
// if (stopped) {
224
// stopped = true;
225
// return false;
226
// }
227
//
228
// DataObject.Container c = (DataObject.Container)
229
// children[i].getCookie(DataObject.Container.class);
230
// if (c != null) {
231
// if (!scanContainer(c)) {
232
// return false;
233
// }
234
// } else {
235
// processSearchObject(children[i]);
236
// }
237
// }
238
//
239
// return true;
240
// }
241

242
243     /** Gets node for found object. Implements superclass method.
244      * @return node delegate for found data object or <code>null</code>
245      * if the object is not of <code>DataObjectType</code> */

246     public Node getNodeForFoundObject(Object JavaDoc object) {
247         if (!(object instanceof DataObject)) {
248             return null;
249         }
250         return ((DataObject) object).getNodeDelegate();
251     }
252     
253     /**
254      * Computes a subset of nodes (search origins) covering all specified nodes.
255      * <p>
256      * Search is performed on trees whose roots are the specified nodes.
257      * If node A is a member of the tree determined by node B, then the A's tree
258      * is a subtree of the B's tree. It means that it is redundant to extra
259      * search the A's tree. This method computes a minimum set of nodes whose
260      * trees cover all nodes' subtrees but does not contain any node not covered
261      * by the original set of nodes.
262      *
263      * @param nodes roots of search trees
264      * @return subset of the original set of nodes
265      * (may be the same object as the parameter)
266      */

267     private static Node[] normalizeNodes(Node[] nodes) {
268         
269         /* No need to normalize: */
270         if (nodes.length < 2) {
271             return nodes;
272         }
273         
274         /*
275          * In the algorithm, we use two sets of nodes: "good nodes" and "bad
276          * nodes". "Good nodes" are nodes not known to be covered by any
277          * search root. "Bad nodes" are nodes known to be covered by at least
278          * one of the search roots.
279          *
280          * Since all the search roots are covered by themselves, they are all
281          * put to "bad nodes" initially. To recognize whether a search root
282          * is covered only by itself or whether it is covered by any other
283          * search root, the former group of nodes has mapped value FALSE
284          * and the later group of nodes has mapped value TRUE.
285          *
286          * Initially, all search roots have mapped value FALSE (not known to be
287          * covered by any other search root) and as the procedure runs, some of
288          * them may be remapped to value TRUE (known to be covered by at least
289          * one other search root).
290          *
291          * The algorithm checks all search roots one by one. The ckeck starts
292          * at a search root to be tested and continues up to its parents until
293          * one of the following:
294          * a) the root of the whole tree of nodes is reached
295          * - i.e. the node being checked is not covered by any other
296          * search root
297          * - mark all the nodes in the path from the node being checked
298          * to the root as "good nodes", except the search root being
299          * checked
300          * - put the search root being checked into the resulting set
301          * of nodes
302          * b) a "good node" is reached
303          * - i.e. neither the good node nor any of the nodes on the path
304          * are covered by any other search root
305          * - mark all the nodes in the path from the node being checked
306          * to the root as "good nodes", except the search root being
307          * checked
308          * - put the search root being checked into the resulting set
309          * of nodes
310          * c) a "bad node" is reached (it may be either another search root
311          * or another "bad node")
312          * - i.e. we know that the reached node is covered by another search
313          * root or the reached node is another search root - in both cases
314          * the search root being checked is covered by another search root
315          * - mark all the nodes in the path from the node being checked
316          * to the root as "bad nodes"; the search root being checked
317          * will be remapped to value TRUE
318          */

319         
320         HashMap JavaDoc badNodes = new HashMap JavaDoc(2 * nodes.length, 0.75f);
321         HashMap JavaDoc goodNodes = new HashMap JavaDoc(2 * nodes.length, 0.75f);
322         ArrayList JavaDoc path = new ArrayList JavaDoc(10);
323         ArrayList JavaDoc result = new ArrayList JavaDoc(nodes.length);
324         
325         /* Put all search roots into "bad nodes": */
326         for (int i = 0; i < nodes.length; i++) {
327             badNodes.put(nodes[i], Boolean.FALSE);
328         }
329         
330         main_cycle:
331         for (int i = 0; i < nodes.length; i++) {
332             path.clear();
333             boolean isBad = false;
334             for (Node n = nodes[i].getParentNode(); n != null;
335                                                     n = n.getParentNode()) {
336                 if (badNodes.containsKey(n)) {
337                     isBad = true;
338                     break;
339                 }
340                 if (goodNodes.containsKey(n)) {
341                     break;
342                 }
343                 path.add(n);
344             }
345             if (isBad) {
346                 badNodes.put(nodes[i], Boolean.TRUE);
347                 for (Iterator JavaDoc j = path.iterator(); j.hasNext(); ) {
348                     badNodes.put(j.next(), Boolean.TRUE);
349                 }
350             } else {
351                 for (Iterator JavaDoc j = path.iterator(); j.hasNext(); ) {
352                     goodNodes.put(j.next(), Boolean.TRUE);
353                 }
354                 result.add(nodes[i]);
355             }
356         }
357         return (Node[]) result.toArray(new Node[result.size()]);
358     }
359
360 }
361
Popular Tags