KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > search > ResultModel


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-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20
21 package org.netbeans.modules.search;
22
23
24 import java.util.*;
25 import org.netbeans.modules.search.types.FullTextType;
26 import org.openide.ErrorManager;
27 import org.openide.nodes.Node;
28 import org.openidex.search.DataObjectSearchGroup;
29 import org.openidex.search.SearchGroup;
30 import org.openidex.search.SearchType;
31
32
33 /**
34  * Holds search result data.
35  *
36  * @author Petr Kuzel
37  * @author Marian Petras
38  */

39 public final class ResultModel {
40
41     /** maximum number of found objects */
42     private static final int COUNT_LIMIT = 500;
43     /** maximum total number of detail entries for found objects */
44     private static final int DETAILS_COUNT_LIMIT = 5000;
45     /** */
46     private static final String JavaDoc DEF_SEARCH_TYPES_PACKAGE
47             = "org.netbeans.modules.search.types"; //NOI18N
48
private static final String JavaDoc FULLTEXT_SEARCH_TYPE
49             = "FullTextType"; //NOI18N
50

51     /** */
52     private final long creationTime;
53     
54     /** */
55     private int size = 0;
56     /** */
57     private int totalDetailsCount = 0;
58     /**
59      */

60     private ResultTreeModel treeModel;
61     /** */
62     private ResultView resultView;
63     
64     /**
65      * flag - did number of found objects reach the limit?
66      *
67      * @see #COUNT_LIMIT
68      */

69     private boolean limitReached = false;
70
71     /** Which search types creates were enabled for this model. */
72     private List<SearchType> searchTypeList;
73
74     /** Search group this result shows search results for. */
75     private SearchGroup searchGroup;
76     
77     /**
78      * is the {@code searchGroup} an instance of class
79      * {@code DataObjectSearchGroup}?
80      *
81      * @see #searchGroup
82      */

83     private final boolean isDataObjectSearchGroup;
84     /**
85      * are all search types defined in the {@code SearchGroup} those
86      * defined in the Utilities module?
87      */

88     final boolean defaultSearchTypesOnly;
89     /** */
90     final boolean fullTextOnly;
91     /** */
92     final FullTextType fullTextSearchType;
93     /** */
94     final String JavaDoc replaceString;
95     /** */
96     final boolean searchAndReplace;
97     /** list of matching objects (usually {@code DataObject}s) */
98     final List<MatchingObject> matchingObjects
99             = new ArrayList<MatchingObject>();
100
101     /** Contains optional finnish message often reason why finished. */
102     private String JavaDoc finishMessage;
103
104     /** Creates new <code>ResultModel</code>. */
105     public ResultModel(List<SearchType> searchTypeList,
106                        SearchGroup searchGroup,
107                        String JavaDoc replaceString) {
108         this.searchTypeList = searchTypeList;
109         this.searchGroup = searchGroup;
110         this.replaceString = replaceString;
111         this.searchAndReplace = (replaceString != null);
112         
113         isDataObjectSearchGroup
114                 = (searchGroup.getClass() == DataObjectSearchGroup.class);
115         boolean hasNonDefaultSearchType = false;
116         FullTextType fullTextType = null;
117         for (SearchType searchType : searchGroup.getSearchTypes()) {
118             Class JavaDoc searchTypeClass = searchType.getClass();
119             String JavaDoc searchTypeName = searchTypeClass.getName();
120             if (searchTypeClass == FullTextType.class) {
121                 fullTextType = (FullTextType) searchType;
122             } else if (!searchTypeName.startsWith(DEF_SEARCH_TYPES_PACKAGE)) {
123                 hasNonDefaultSearchType = true;
124             }
125             if (hasNonDefaultSearchType && (fullTextType != null)) {
126                 break;
127             }
128         }
129         defaultSearchTypesOnly = !hasNonDefaultSearchType;
130         fullTextSearchType = fullTextType;
131         fullTextOnly = (searchAndReplace || defaultSearchTypesOnly)
132                        && (fullTextSearchType != null);
133         
134         creationTime = System.currentTimeMillis();
135     }
136     
137     /**
138      */

139     long getCreationTime() {
140         return creationTime;
141     }
142     
143     /**
144      * Sets an observer which will be notified whenever an object is found.
145      *
146      * @param observer observer or <code>null</code>
147      */

148     void setObserver(ResultTreeModel observer) {
149         this.treeModel = observer;
150     }
151     
152     /**
153      * Sets an observer which will be notified whenever an object is found.
154      *
155      * @param observer observer or <code>null</code>
156      */

157     void setObserver(ResultView observer) {
158         this.resultView = observer;
159     }
160
161     /**
162      * Clean the allocated resources. Do not rely on GC there as we are often referenced from
163      * various objects (some VisualizerNode realy loves us). So keep leak as small as possible.
164      * */

165     void close() {
166         if ((matchingObjects != null) && !matchingObjects.isEmpty()) {
167             for (MatchingObject matchingObj : matchingObjects) {
168                 matchingObj.cleanup();
169             }
170         }
171         
172         if (searchTypeList != null){
173             for (SearchType searchType : searchTypeList) {
174                 /*
175                  * HACK:
176                  * GC should eliminate FullTextType details map but it does not,
177                  * so we force cleaning of the map
178                  */

179                 if (searchType instanceof //XXX - hack
180
org.netbeans.modules.search.types.FullTextType) {
181                     ((org.netbeans.modules.search.types.FullTextType)searchType)
182                     .destroy();
183                 }
184             }
185             searchTypeList.clear();
186             searchTypeList = null;
187         }
188
189         // eliminate search group content
190
// no other way then leaving it on GC, it should work because
191
// search group is always recreated by a it's factory and
192
// nobody keeps reference to it. 7th May 2004
193

194         searchGroup = null;
195     }
196     
197     /**
198      * Notifies ths result model of a newly found matching object.
199      *
200      * @param object matching object
201      * @return {@code true} if this result model can accept more objects,
202      * {@code false} if number of found objects reached the limit
203      */

204     synchronized boolean objectFound(Object JavaDoc object) {
205         MatchingObject matchingObject = new MatchingObject(this, object);
206         if (matchingObjects.add(matchingObject) == false) {
207             return true;
208         }
209         
210         assert limitReached == false;
211         assert treeModel != null;
212         assert resultView != null;
213         
214         totalDetailsCount += getDetailsCount(matchingObject);
215         
216         treeModel.objectFound(matchingObject, size++);
217         resultView.objectFound(matchingObject, totalDetailsCount);
218         
219         return size < COUNT_LIMIT && totalDetailsCount < DETAILS_COUNT_LIMIT;
220     }
221     
222     /**
223      */

224     public void objectBecameInvalid(MatchingObject matchingObj) {
225         
226         /* may be called from non-EDT thread */
227         
228         int index = matchingObjects.indexOf(matchingObj);
229         assert index != -1;
230         
231         treeModel.objectBecameInvalid(matchingObj);
232     }
233     
234     /**
235      */

236     synchronized int getTotalDetailsCount() {
237         return totalDetailsCount;
238     }
239     
240     /**
241      */

242     synchronized MatchingObject[] getMatchingObjects() {
243         return matchingObjects.toArray(
244                                     new MatchingObject[matchingObjects.size()]);
245     }
246     
247     /**
248      */

249     synchronized Object JavaDoc[] getFoundObjects() {
250         Object JavaDoc[] foundObjects = new Object JavaDoc[matchingObjects.size()];
251         int index = 0;
252         for (MatchingObject matchingObj : matchingObjects) {
253             foundObjects[index++] = matchingObj.object;
254         }
255         return foundObjects;
256     }
257     
258     public void run() {
259         
260     }
261     
262     /**
263      */

264     boolean hasDetails() {
265         return totalDetailsCount != 0; //PENDING - synchronization?
266
}
267     
268     /**
269      * Performs a quick check whether
270      * {@linkplain MatchingObject matching objects} contained in this model
271      * can have details.
272      *
273      * @return {@code Boolean.TRUE} if all matching objects have details,
274      * {@code Boolean.FALSE} if no matching object has details,
275      * {@code null} if matching objects may have details
276      * (if more time consuming check would be necessary)
277      */

278     Boolean JavaDoc canHaveDetails() {
279         Boolean JavaDoc ret;
280         if (fullTextSearchType != null) {
281             ret = Boolean.TRUE;
282         } else if (defaultSearchTypesOnly) {
283             ret = Boolean.FALSE;
284         } else {
285             ret = null;
286         }
287         return ret;
288     }
289     
290     /*
291      * A cache exists for information about a single MatchingObject
292      * to prevent from repetitive calls of time-consuming queries on
293      * number of details and list of details. These calls are initiated
294      * by the node renderer (class NodeRenderer).
295      */

296     
297     private MatchingObject infoCacheMatchingObject;
298     private Boolean JavaDoc infoCacheHasDetails;
299     private int infoCacheDetailsCount;
300     private Node[] infoCacheDetailNodes;
301     private final Node[] EMPTY_NODES_ARRAY = new Node[0];
302     
303     /**
304      */

305     private void prepareCacheFor(MatchingObject matchingObject) {
306         if (matchingObject != infoCacheMatchingObject) {
307             infoCacheHasDetails = null;
308             infoCacheDetailsCount = -1;
309             infoCacheDetailNodes = null;
310             infoCacheMatchingObject = matchingObject;
311         }
312     }
313     
314     /**
315      */

316     boolean hasDetails(MatchingObject matchingObject) {
317         prepareCacheFor(matchingObject);
318         if (infoCacheHasDetails != null) {
319             return infoCacheHasDetails.booleanValue();
320         }
321         
322         boolean hasDetails = hasDetailsReal(matchingObject);
323         infoCacheHasDetails = Boolean.valueOf(hasDetails);
324         
325         assert (infoCacheHasDetails == Boolean.TRUE)
326                || (infoCacheHasDetails == Boolean.FALSE);
327         return hasDetails;
328     }
329     
330     /**
331      */

332     private boolean hasDetailsReal(MatchingObject matchingObject) {
333         boolean ret;
334         if (fullTextSearchType != null) {
335             ret = true;
336         } else if (defaultSearchTypesOnly) {
337             ret = false;
338         } else {
339             ret = false;
340             final Object JavaDoc foundObject = matchingObject.object;
341             for (SearchType searchType : searchGroup.getSearchTypes()) {
342                 Node[] detailNodes = searchType.getDetails(foundObject);
343                 if ((detailNodes != null) && (detailNodes.length != 0)) {
344                     ret = true;
345                     break;
346                 }
347             }
348         }
349         return ret;
350     }
351     
352     /**
353      */

354     int getDetailsCount(MatchingObject matchingObject) {
355         prepareCacheFor(matchingObject);
356         if (infoCacheDetailsCount == -1) {
357             infoCacheDetailsCount = getDetailsCountReal(matchingObject);
358             if (infoCacheDetailsCount == 0) {
359                 infoCacheDetailNodes = EMPTY_NODES_ARRAY;
360             }
361         }
362         
363         assert infoCacheDetailsCount >= 0;
364         return infoCacheDetailsCount;
365     }
366     
367     /**
368      * Returns number of detail nodes available to the given found object.
369      *
370      * @param foundObject object matching the search criteria
371      * @return number of detail items (represented by individual nodes)
372      * available for the given object (usually {@code DataObject})
373      */

374     private int getDetailsCountReal(MatchingObject matchingObject) {
375         if (defaultSearchTypesOnly) {
376             return (fullTextSearchType != null)
377                    ? fullTextSearchType.getDetailsCount(matchingObject.object)
378                    : 0;
379         }
380         
381         int count = 0;
382         final Object JavaDoc foundObject = matchingObject.object;
383         for (SearchType searchType : searchGroup.getSearchTypes()) {
384             if (searchType == fullTextSearchType) {
385                 count += fullTextSearchType.getDetailsCount(foundObject);
386             } else {
387                 Node[] detailNodes = searchType.getDetails(foundObject);
388                 count += (detailNodes != null) ? detailNodes.length : 0;
389             }
390         }
391         return count;
392     }
393     
394     /**
395      *
396      * @return non-empty array of detail nodes
397      * or {@code null} if there are no detail nodes
398      */

399     Node[] getDetails(MatchingObject matchingObject) {
400         prepareCacheFor(matchingObject);
401         Node[] detailNodes;
402         if (infoCacheDetailNodes == null) {
403             detailNodes = getDetailsReal(matchingObject);
404             infoCacheDetailNodes = (detailNodes != null)
405                                    ? detailNodes
406                                    : EMPTY_NODES_ARRAY;
407             infoCacheDetailsCount = infoCacheDetailNodes.length;
408         } else {
409             detailNodes = (infoCacheDetailNodes != EMPTY_NODES_ARRAY)
410                           ? infoCacheDetailNodes
411                           : null;
412         }
413         
414         assert (infoCacheDetailNodes != null)
415                && ((infoCacheDetailNodes == EMPTY_NODES_ARRAY)
416                    || (infoCacheDetailNodes.length > 0));
417         assert (detailNodes == null) || (detailNodes.length > 0);
418         return detailNodes;
419     }
420     
421     /**
422      *
423      * @return non-empty array of detail nodes
424      * or {@code null} if there are no detail nodes
425      */

426     private Node[] getDetailsReal(MatchingObject matchingObject) {
427         if (defaultSearchTypesOnly) {
428             return (fullTextSearchType != null)
429                    ? fullTextSearchType.getDetails(matchingObject.object)
430                    : null;
431         }
432         
433         Node[] nodesTotal = null;
434         final Object JavaDoc foundObject = matchingObject.object;
435         for (SearchType searchType : searchGroup.getSearchTypes()) {
436             Node[] detailNodes = searchType.getDetails(foundObject);
437             if ((detailNodes == null) || (detailNodes.length == 0)) {
438                 continue;
439             }
440             if (nodesTotal == null) {
441                 nodesTotal = detailNodes;
442             } else {
443                 Node[] oldNodesTotal = nodesTotal;
444                 nodesTotal = new Node[nodesTotal.length + detailNodes.length];
445                 System.arraycopy(oldNodesTotal, 0,
446                                  nodesTotal, 0,
447                                  oldNodesTotal.length);
448                 System.arraycopy(detailNodes, 0,
449                                  nodesTotal, oldNodesTotal.length,
450                                  detailNodes.length);
451             }
452         }
453         return nodesTotal;
454     }
455     
456     /**
457      */

458     synchronized int size() {
459         return size;
460     }
461     
462     /**
463      */

464     boolean isEmpty() {
465         return size == 0;
466     }
467
468     /** Getter for search group property. */
469     SearchGroup getSearchGroup() {
470         return searchGroup;
471     }
472     
473     /** Gets all search types, all enabled not only customized ones. */
474     List getEnabledSearchTypes() {
475         return searchTypeList;
476     }
477     
478     /**
479      * Returns search types that were used during the search.
480      *
481      * @return array of <code>SearchType</code>s that each tested object was
482      * tested for compliance
483      */

484     SearchType[] getQueriedSearchTypes() {
485         return searchGroup.getSearchTypes();
486     }
487
488     /**
489      */

490     boolean wasLimitReached() {
491         return limitReached;
492     }
493
494     /** This exception stoped search */
495     void searchException(RuntimeException JavaDoc ex) {
496         ErrorManager.Annotation[] annotations = ErrorManager.getDefault().findAnnotations(ex);
497         for (int i = 0; i < annotations.length; i++) {
498             ErrorManager.Annotation annotation = annotations[i];
499             if (annotation.getSeverity() == ErrorManager.USER) {
500                 finishMessage = annotation.getLocalizedMessage();
501                 if (finishMessage != null) return;
502             }
503         }
504         finishMessage = ex.getLocalizedMessage();
505     }
506     
507     /**
508      */

509     String JavaDoc getExceptionMsg() {
510         return finishMessage;
511     }
512
513 }
514
Popular Tags