• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   - Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *
11  *   - Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *   - Neither the name of Oracle nor the names of its
16  *     contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * This source code is provided to illustrate the usage of a given feature
34  * or technique and has been deliberately simplified. Additional steps
35  * required for a production-quality application, such as security checks,
36  * input validation, and proper error handling, might not be present in
37  * this sample code.
38  */
39 
40 import java.io.IOException;
41 import java.io.UncheckedIOException;
42 import java.nio.file.Files;
43 import java.nio.file.Path;
44 import java.nio.file.Paths;
45 import java.util.Arrays;
46 import java.util.List;
47 import java.util.regex.Pattern;
48 import java.util.stream.Stream;
49 
50 import static java.util.stream.Collectors.toList;
51 
52 /**
53  * Grep prints lines matching a regex. See {@link #printUsageAndExit(String...)}
54  * method for instructions and command line parameters. This sample shows
55  * examples of using next features:
56  * <ul>
57  * <li>Lambda and bulk operations. Working with streams:
58  * map(...),filter(...),flatMap(...),limit(...) methods.</li>
59  * <li>Static method reference for printing values.</li>
60  * <li>New Collections API forEach(...) method.</li>
61  * <li>Try-with-resources feature.</li>
62  * <li>new Files.walk(...), Files.lines(...) API.</li>
63  * <li>Streams that need to be closed.</li>
64  * </ul>
65  *
66  */
67 public class Grep {
68 
printUsageAndExit(String... str)69     private static void printUsageAndExit(String... str) {
70         System.out.println("Usage: " + Grep.class.getSimpleName()
71                 + " [OPTION]... PATTERN FILE...");
72         System.out.println("Search for PATTERN in each FILE. "
73                 + "If FILE is a directory then whole file tree of the directory"
74                 + " will be processed.");
75         System.out.println("Example: grep -m 100 'hello world' menu.h main.c");
76         System.out.println("Options:");
77         System.out.println("    -m NUM: stop analysis after NUM matches");
78         Arrays.asList(str).forEach(System.err::println);
79         System.exit(1);
80     }
81 
82     /**
83      * The main method for the Grep program. Run program with empty argument
84      * list to see possible arguments.
85      *
86      * @param args the argument list for Grep.
87      * @throws java.io.IOException If an I/O error occurs.
88      */
main(String[] args)89     public static void main(String[] args) throws IOException {
90         long maxCount = Long.MAX_VALUE;
91         if (args.length < 2) {
92             printUsageAndExit();
93         }
94         int i = 0;
95         //parse OPTIONS
96         while (args[i].startsWith("-")) {
97             switch (args[i]) {
98                 case "-m":
99                     try {
100                         maxCount = Long.parseLong(args[++i]);
101                     } catch (NumberFormatException ex) {
102                         printUsageAndExit(ex.toString());
103                     }
104                     break;
105                 default:
106                     printUsageAndExit("Unexpected option " + args[i]);
107             }
108             i++;
109         }
110         //parse PATTERN
111         Pattern pattern = Pattern.compile(args[i++]);
112         if (i == args.length) {
113             printUsageAndExit("There are no files for input");
114         }
115 
116         try {
117             /*
118             * First obtain the list of all paths.
119             * For a small number of arguments there is little to be gained
120             * by producing this list in parallel. For one argument
121             * there will be no parallelism.
122             *
123             * File names are converted to paths. If a path is a directory then
124             * Stream is populated with whole file tree of the directory by
125             * flatMap() method. Files are filtered from directories.
126             */
127             List<Path> files = Arrays.stream(args, i, args.length)
128                     .map(Paths::get)
129                     // flatMap will ensure each I/O-based stream will be closed
130                     .flatMap(Grep::getPathStream)
131                     .filter(Files::isRegularFile)
132                     .collect(toList());
133             /*
134             * Then operate on that list in parallel.
135             * This is likely to give a more even distribution of work for
136             * parallel execution.
137             *
138             * Lines are extracted from files. Lines are filtered by pattern.
139             * Stream is limited by number of matches. Each remaining string is
140             * displayed in std output by method reference System.out::println.
141             */
142             files.parallelStream()
143                     // flatMap will ensure each I/O-based stream will be closed
144                     .flatMap(Grep::path2Lines)
145                     .filter(pattern.asPredicate())
146                     .limit(maxCount)
147                     .forEachOrdered(System.out::println);
148         } catch (UncheckedIOException ioe) {
149             printUsageAndExit(ioe.toString());
150         }
151     }
152 
153     /**
154      * Flattens file system hierarchy into a stream. This code is not inlined
155      * for the reason of Files.walk() throwing a checked IOException that must
156      * be caught.
157      *
158      * @param path - the file or directory
159      * @return Whole file tree starting from path, a stream with one element -
160      * the path itself - if it is a file.
161      */
getPathStream(Path path)162     private static Stream<Path> getPathStream(Path path) {
163         try {
164             return Files.walk(path);
165         } catch (IOException e) {
166             throw new UncheckedIOException(e);
167         }
168     }
169 
170     /**
171      * Produces a stream of lines from a file. The result is a stream in order
172      * to close it later. This code is not inlined for the reason of
173      * Files.lines() throwing a checked IOException that must be caught.
174      *
175      * @param path - the file to read
176      * @return stream of lines from the file
177      */
path2Lines(Path path)178     private static Stream<String> path2Lines(Path path) {
179         try {
180             return Files.lines(path);
181         } catch (IOException e) {
182             throw new UncheckedIOException(e);
183         }
184     }
185 }
186