This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 193361
Collapse All | Expand All

(-)a/o.openidex.util/manifest.mf (-1 / +1 lines)
Lines 1-5 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.openidex.util/3
2
OpenIDE-Module: org.openidex.util/3
3
OpenIDE-Module-Localizing-Bundle: org/openidex/resources/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/openidex/resources/Bundle.properties
4
OpenIDE-Module-Specification-Version: 3.30
4
OpenIDE-Module-Specification-Version: 3.31
5
AutoUpdate-Essential-Module: true
5
AutoUpdate-Essential-Module: true
(-)a/o.openidex.util/src/org/openidex/search/SearchGroup.java (+14 lines)
Lines 164-172 Link Here
164
        return searchRoots.toArray(new Node[searchRoots.size()]);
164
        return searchRoots.toArray(new Node[searchRoots.size()]);
165
    }
165
    }
166
    
166
    
167
    /** This method is invoked when the current search is being stopped.
168
     * 
169
     * You can override it to terminate any internal tasks that have been 
170
     * started to process individual found items and that take a long time 
171
     * to finish.
172
     * 
173
     * The default implementation does nothing.
174
     * 
175
     * @since  org.openidex.util/3 3.31
176
     */
177
    protected void onStopSearch() {
178
    }
179
    
167
    /** Stops searching. */
180
    /** Stops searching. */
168
    public final void stopSearch() {
181
    public final void stopSearch() {
169
        stopped = true;
182
        stopped = true;
183
        onStopSearch();
170
    }
184
    }
171
185
172
    /**
186
    /**
(-)a/o.openidex.util/test/unit/src/org/openidex/search/SearchGroupTest.java (+153 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common Development and
11
 * Distribution License("CDDL") (collectively, the "License"). You may not use
12
 * this file except in compliance with the License. You can obtain a copy of
13
 * the License at http://www.netbeans.org/cddl-gplv2.html or
14
 * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
15
 * governing permissions and limitations under the License. When distributing
16
 * the software, include this License Header Notice in each file and include
17
 * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
18
 * particular file as subject to the "Classpath" exception as provided by
19
 * Oracle in the GPL Version 2 section of the License file that accompanied
20
 * this code. If applicable, add the following below the License Header, with
21
 * the fields enclosed by brackets [] replaced by your own identifying
22
 * information: "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL or
25
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
26
 * elects to include this software in this distribution under the [CDDL or GPL
27
 * Version 2] license." If you do not indicate a single choice of license, a
28
 * recipient has the option to distribute your version of this file under
29
 * either the CDDL, the GPL Version 2 or to extend the choice of license to its
30
 * licensees as provided above. However, if you add GPL Version 2 code and
31
 * therefore, elected the GPL Version 2 license, then the option applies only
32
 * if the new code is made subject to such option by the copyright holder.
33
 *
34
 * Contributor(s):
35
 *
36
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
37
 */
38
package org.openidex.search;
39
40
import java.util.concurrent.atomic.AtomicBoolean;
41
import org.netbeans.junit.NbTestCase;
42
import org.openide.nodes.Node;
43
44
/**
45
 *
46
 * @author jhavlin
47
 */
48
public class SearchGroupTest extends NbTestCase {
49
50
    public SearchGroupTest(String name) {
51
        super(name);
52
    }
53
54
    /** Test that SearchGroup.onStopSearch is invoked properly.     
55
     */
56
    public void testOnStopSearchPositive() throws InterruptedException {
57
58
        FakeSearchGroup fsg = new FakeSearchGroup() {
59
60
            @Override
61
            protected void onStopSearch() {
62
                getInnerTaks().terminate();
63
            }
64
        };
65
        try {
66
            Thread searchThread = new Thread(new SearchRunner(fsg));
67
            searchThread.start();
68
            Thread.sleep(10);
69
            assertTrue("Search should be running now", searchThread.isAlive());
70
            fsg.stopSearch();
71
            Thread.sleep(10);
72
            assertFalse("Search has not been stopped", searchThread.isAlive());
73
            
74
        } finally {
75
            fsg.innerTask.terminate();        
76
        }
77
    }
78
79
    /** Test that long-running internal task is not terminated unless
80
     * method SearchGroup.onStopSearch is overriden to manage it.
81
     */
82
    public void testOnStopSearchNegative() throws InterruptedException {
83
84
        FakeSearchGroup fsg = new FakeSearchGroup();
85
        try {
86
            Thread searchThread = new Thread(new SearchRunner(fsg));
87
            searchThread.start();
88
            Thread.sleep(10);
89
            assertTrue("Search should be running now", searchThread.isAlive());
90
            fsg.stopSearch();
91
            Thread.sleep(10);
92
            assertTrue("Search should be still running", searchThread.isAlive());
93
            fsg.getInnerTaks().terminate(); // terminate inner task explicitly
94
            Thread.sleep(10);
95
            assertFalse("Inner task wasn't stopped", searchThread.isAlive());
96
        } finally {
97
            fsg.getInnerTaks().terminate();
98
        }
99
    }
100
101
    /** Helper class for simulating internal long-running job. */
102
    private static class TerminatableLongTask {
103
104
        private AtomicBoolean stopped = new AtomicBoolean(false);
105
106
        public void start() {
107
            while (!stopped.get()) {
108
            }
109
        }
110
111
        public final void terminate() {
112
            stopped.set(true);
113
        }
114
    }
115
116
    /** Helper trivial implementation of SearchGroup that contains internal
117
     * long-running task. */
118
    private static class FakeSearchGroup extends SearchGroup {
119
120
        private TerminatableLongTask innerTask = new TerminatableLongTask();
121
122
        @Override
123
        protected void doSearch() {
124
            innerTask.start();
125
        }
126
127
        @Override
128
        public Node getNodeForFoundObject(Object object) {
129
            throw new UnsupportedOperationException("Not supported yet.");
130
        }
131
132
        public TerminatableLongTask getInnerTaks() {
133
            return innerTask;
134
        }
135
    }
136
137
    /** Helper Runnable for starting a search group in a new thread.     
138
     */
139
    private static class SearchRunner implements Runnable {
140
141
        private SearchGroup sg;
142
143
        public SearchRunner(SearchGroup sg) {
144
            this.sg = sg;
145
        }
146
147
        @Override
148
        public void run() {
149
            sg.prepareSearch();
150
            sg.doSearch();
151
        }
152
    }
153
}
(-)a/utilities/nbproject/project.xml (-1 / +1 lines)
Lines 194-200 Link Here
194
                    <compile-dependency/>
194
                    <compile-dependency/>
195
                    <run-dependency>
195
                    <run-dependency>
196
                        <release-version>3</release-version>
196
                        <release-version>3</release-version>
197
                        <specification-version>3.20</specification-version>
197
                        <specification-version>3.31</specification-version>
198
                    </run-dependency>
198
                    </run-dependency>
199
                </dependency>
199
                </dependency>
200
            </module-dependencies>
200
            </module-dependencies>
(-)a/utilities/src/org/netbeans/modules/search/BasicSearchCriteria.java (-1 / +89 lines)
Lines 66-71 Link Here
66
import org.openide.loaders.DataObject;
66
import org.openide.loaders.DataObject;
67
import org.openide.loaders.DataObjectNotFoundException;
67
import org.openide.loaders.DataObjectNotFoundException;
68
import org.openide.nodes.Node;
68
import org.openide.nodes.Node;
69
import org.openide.util.NbBundle;
69
import org.openidex.search.SearchPattern;
70
import org.openidex.search.SearchPattern;
70
import static java.util.logging.Level.FINER;
71
import static java.util.logging.Level.FINER;
71
import static java.util.logging.Level.FINEST;
72
import static java.util.logging.Level.FINEST;
Lines 91-96 Link Here
91
92
92
    /** array of searchable application/x-<em>suffix</em> MIME-type suffixes */
93
    /** array of searchable application/x-<em>suffix</em> MIME-type suffixes */
93
    private static final Collection<String> searchableXMimeTypes;
94
    private static final Collection<String> searchableXMimeTypes;
95
96
    /** List of currently processed searches. */
97
    private List<BufferedCharSequence> currentlyProcessedSequences =
98
            new ArrayList<BufferedCharSequence>(1);
99
    
100
    /** Termination flag */
101
    private boolean terminated = false;
94
    
102
    
95
    static {
103
    static {
96
        searchableXMimeTypes = new HashSet<String>(17);
104
        searchableXMimeTypes = new HashSet<String>(17);
Lines 670-675 Link Here
670
        
678
        
671
        assert !textPatternValid || (textPattern != null);
679
        assert !textPatternValid || (textPattern != null);
672
        assert !fileNamePatternValid || (fileNamePattern != null);
680
        assert !fileNamePatternValid || (fileNamePattern != null);
681
        synchronized (this) {
682
            terminated = false;
683
            currentlyProcessedSequences.clear();
684
        }
673
    }
685
    }
674
    
686
    
675
    /**
687
    /**
Lines 767-779 Link Here
767
     */
779
     */
768
    private boolean checkFileContent(FileObject fo) {
780
    private boolean checkFileContent(FileObject fo) {
769
        assert fo != null;
781
        assert fo != null;
782
        assureMemory(fo);
770
        lastCharset = FileEncodingQuery.getEncoding(fo);
783
        lastCharset = FileEncodingQuery.getEncoding(fo);
771
        SearchPattern sp = createSearchPattern();
784
        SearchPattern sp = createSearchPattern();
772
        BufferedCharSequence bcs = null;
785
        BufferedCharSequence bcs = null;
773
        try {         
786
        try {         
774
            InputStream stream = fo.getInputStream();
787
            InputStream stream = fo.getInputStream();
775
            bcs = new BufferedCharSequence(stream, lastCharset, fo.getSize());
788
            bcs = new BufferedCharSequence(stream, lastCharset, fo.getSize());
789
            registerProcessedSequence(bcs);
776
            ArrayList<TextDetail> txtDetails = getTextDetails(bcs, fo, sp);
790
            ArrayList<TextDetail> txtDetails = getTextDetails(bcs, fo, sp);
791
            unregisterProcessedSequence(bcs);
777
            if (txtDetails.isEmpty()){                
792
            if (txtDetails.isEmpty()){                
778
                return false;
793
                return false;
779
            }            
794
            }            
Lines 818-823 Link Here
818
        return false;
833
        return false;
819
    }
834
    }
820
835
836
    /** Assure that there is enough available memory for searching in file.
837
     * Idea and code copied from org.openidex.search.DataObjectSearchGroup.
838
     * Uses rough estimate of memory requirements based on file size. 
839
     */
840
    private void assureMemory(FileObject fo) {
841
842
        long fileSize = fo.getSize();
843
        long requiredEstimate = fileSize * 3;
844
        if ((int) requiredEstimate < 0) {
845
            // Integer overflow.
846
            throwNoMemoryExeption(fo, fileSize);
847
        }
848
        if (getAvailableMemory() < requiredEstimate) {
849
            System.gc();
850
            try {
851
                byte[] gcProvocation = new byte[(int) requiredEstimate];
852
                gcProvocation[(int) fileSize] = 42;
853
                gcProvocation = null;
854
            } catch (OutOfMemoryError ooe) {
855
                throwNoMemoryExeption(fo, fileSize);
856
            }
857
        }
858
    }
859
860
    /** Get approximation of available memory in bytes. */
861
    private long getAvailableMemory() {
862
863
        Runtime rt = Runtime.getRuntime();
864
865
        long max = rt.maxMemory();
866
        long free = rt.freeMemory();
867
        long total = rt.totalMemory();
868
869
        long available = (max - total) + free;
870
        return available;
871
    }
872
873
    /** Throw an exception telling that there is not enough memory for searching
874
     * in a file. 
875
     */
876
    private void throwNoMemoryExeption(FileObject fo, long fileSize) {
877
        String text = NbBundle.getMessage(
878
                BasicSearchCriteria.class, "TEXT_MSG_NOT_ENOUGH_MEMORY",
879
                fo.getNameExt(), fileSize / 1024);
880
        throw new RuntimeException(text);
881
    }
882
821
    private ArrayList<TextDetail> getTextDetails(BufferedCharSequence bcs,
883
    private ArrayList<TextDetail> getTextDetails(BufferedCharSequence bcs,
822
                                                 FileObject fo,
884
                                                 FileObject fo,
823
                                                 SearchPattern sp)
885
                                                 SearchPattern sp)
Lines 827-834 Link Here
827
        ArrayList<TextDetail> txtDetails = new ArrayList<TextDetail>();
889
        ArrayList<TextDetail> txtDetails = new ArrayList<TextDetail>();
828
        FindState fs = new FindState(bcs);
890
        FindState fs = new FindState(bcs);
829
891
892
        final int limit = ResultModel.Limit.MATCHES_COUNT_LIMIT.getValue();        
830
        Matcher matcher = textPattern.matcher(bcs);
893
        Matcher matcher = textPattern.matcher(bcs);
831
        while (matcher.find()) {
894
        while (matcher.find() && txtDetails.size() < limit) {
832
            int matcherStart = matcher.start();
895
            int matcherStart = matcher.start();
833
896
834
            int column = fs.calcColumn(matcherStart);
897
            int column = fs.calcColumn(matcherStart);
Lines 1027-1030 Link Here
1027
        }
1090
        }
1028
    } // FindState
1091
    } // FindState
1029
1092
1093
    /** Register BufferedCharSequence that is being processed by this object.
1094
     * It is used when user needs to terminate the current search. */
1095
    private synchronized void registerProcessedSequence(
1096
            BufferedCharSequence bcs) throws IOException {        
1097
        if (terminated) {
1098
            bcs.close();
1099
        } else {
1100
            currentlyProcessedSequences.add(bcs);
1101
        }
1102
    }
1103
    
1104
    /** Unregister a BufferedCharSequence after it was processed. */
1105
    private synchronized void unregisterProcessedSequence(
1106
            BufferedCharSequence bcc) {
1107
        currentlyProcessedSequences.remove(bcc);
1108
    }
1109
    
1110
    /** Stop all searches that are processed by this instance. */
1111
    synchronized void terminateCurrentSearches() throws IOException {
1112
        for (BufferedCharSequence bcs: currentlyProcessedSequences) {
1113
            bcs.close();
1114
        }
1115
        currentlyProcessedSequences.clear();
1116
        terminated = true;
1117
    }
1030
}
1118
}
(-)a/utilities/src/org/netbeans/modules/search/BufferedCharSequence.java (-7 / +9 lines)
Lines 230-242 Link Here
230
     * @return the underlying instance of this class.
230
     * @return the underlying instance of this class.
231
     * @throws IOException if an I/O error occurs.
231
     * @throws IOException if an I/O error occurs.
232
     */
232
     */
233
    public BufferedCharSequence close() throws IOException {
233
    public synchronized BufferedCharSequence close() throws IOException {
234
        reset();
234
        if (!isClosed) {
235
        source.close();
235
            reset();
236
        source = null;
236
            source.close();
237
        sink = null;
237
            source = null;
238
        coderResult = null;
238
            sink = null;
239
        isClosed = true;
239
            coderResult = null;
240
            isClosed = true;
241
        }
240
        return this;
242
        return this;
241
    }
243
    }
242
244
(-)a/utilities/src/org/netbeans/modules/search/Bundle.properties (+1 lines)
Lines 109-114 Link Here
109
TEXT_MSG_FOUND_X_NODES_LIMIT=Found {1} {1,choice,1#match|1<matches} in {0} {0,choice,1#file|1<files} so far.
109
TEXT_MSG_FOUND_X_NODES_LIMIT=Found {1} {1,choice,1#match|1<matches} in {0} {0,choice,1#file|1<files} so far.
110
TEXT_MSG_LIMIT_REACHED_FILES_COUNT=The search was stopped because the limit for number of matching files ({0,number}) was reached.
110
TEXT_MSG_LIMIT_REACHED_FILES_COUNT=The search was stopped because the limit for number of matching files ({0,number}) was reached.
111
TEXT_MSG_LIMIT_REACHED_MATCHES_COUNT=The search was stopped because the limit for number of matching occurences ({0,number}) was reached or exceeded.
111
TEXT_MSG_LIMIT_REACHED_MATCHES_COUNT=The search was stopped because the limit for number of matching occurences ({0,number}) was reached or exceeded.
112
TEXT_MSG_NOT_ENOUGH_MEMORY=The search was stopped. Not enough memory for checking file {0} ({1} KiB)
112
TEXT_PREPARE_SEARCH___=Preparing data for searching...
113
TEXT_PREPARE_SEARCH___=Preparing data for searching...
113
TEXT_SEARCHING___=Searching...
114
TEXT_SEARCHING___=Searching...
114
TEXT_FINISHING_PREV_SEARCH=Finishing the previous search...
115
TEXT_FINISHING_PREV_SEARCH=Finishing the previous search...
(-)a/utilities/src/org/netbeans/modules/search/Manager.java (-2 / +4 lines)
Lines 605-612 Link Here
605
        if (pendingTasks.remove(sTask)){
605
        if (pendingTasks.remove(sTask)){
606
            notifySearchCancelled(sTask);
606
            notifySearchCancelled(sTask);
607
        } else if (currentTasks.contains(sTask)){
607
        } else if (currentTasks.contains(sTask)){
608
            stoppingTasks.add(sTask);
608
            if (!stoppingTasks.contains(sTask)) {
609
            sTask.stop();
609
                stoppingTasks.add(sTask);
610
                sTask.stop();
611
            }            
610
        }
612
        }
611
    }
613
    }
612
614
(-)a/utilities/src/org/netbeans/modules/search/ResultModel.java (-3 / +7 lines)
Lines 74-88 Link Here
74
                            DETAILS_COUNT_LIMIT);
74
                            DETAILS_COUNT_LIMIT);
75
75
76
        private final String bundleKey;
76
        private final String bundleKey;
77
        private final Integer msgParam;
77
        private final Integer value;
78
78
79
        private Limit(String bundleKey, Integer limit) {
79
        private Limit(String bundleKey, Integer limit) {
80
            this.bundleKey = bundleKey;
80
            this.bundleKey = bundleKey;
81
            this.msgParam = limit;
81
            this.value = limit;
82
        }
82
        }
83
83
84
        String getDisplayName() {
84
        String getDisplayName() {
85
            return NbBundle.getMessage(Limit.class, bundleKey, msgParam);
85
            return NbBundle.getMessage(Limit.class, bundleKey, value);
86
        }
87
        
88
        public Integer getValue() {
89
            return this.value;
86
        }
90
        }
87
    }
91
    }
88
92
(-)a/utilities/src/org/netbeans/modules/search/SpecialSearchGroup.java (-1 / +12 lines)
Lines 44-55 Link Here
44
44
45
package org.netbeans.modules.search;
45
package org.netbeans.modules.search;
46
46
47
import java.io.IOException;
47
import java.nio.charset.Charset;
48
import java.nio.charset.Charset;
48
import java.util.Collection;
49
import java.util.Collection;
49
import java.util.Iterator;
50
import java.util.Iterator;
50
import java.util.LinkedList;
51
import java.util.LinkedList;
51
import org.openide.filesystems.FileObject;
52
import org.openide.filesystems.FileObject;
52
import org.openide.loaders.DataObject;
53
import org.openide.loaders.DataObject;
54
import org.openide.util.Exceptions;
53
import org.openidex.search.DataObjectSearchGroup;
55
import org.openidex.search.DataObjectSearchGroup;
54
import org.openidex.search.SearchInfo;
56
import org.openidex.search.SearchInfo;
55
import org.openidex.search.SearchType;
57
import org.openidex.search.SearchType;
Lines 195-199 Link Here
195
    SearchScope getSearchScope(){
197
    SearchScope getSearchScope(){
196
        return searchScope;
198
        return searchScope;
197
    }
199
    }
198
    
200
201
    @Override
202
    protected void onStopSearch() {        
203
        try {
204
            basicCriteria.terminateCurrentSearches();
205
        } catch (IOException ex) {
206
            Exceptions.printStackTrace(ex);
207
            throw new RuntimeException(ex);
208
        }
209
    }            
199
}
210
}

Return to bug 193361