View Javadoc
1   /**************************************************************************
2    *
3    * Copyright (c) 2016-2020 Yawg project contributors.
4    *
5    **************************************************************************/
6   
7   package com.varmateo.yawg.util;
8   
9   import java.nio.file.FileSystem;
10  import java.nio.file.FileSystems;
11  import java.nio.file.Path;
12  import java.nio.file.PathMatcher;
13  import java.util.function.Predicate;
14  import java.util.regex.PatternSyntaxException;
15  
16  import io.vavr.collection.Array;
17  import io.vavr.collection.Seq;
18  
19  
20  /**
21   * A predicate for checking if a path matches a given collection of
22   * glob patterns.
23   */
24  public final class GlobMatcher
25          implements Predicate<Path> {
26  
27  
28      private static final FileSystem DEFAULT_FILESYSTEM =
29              FileSystems.getDefault();
30  
31  
32      private final Seq<String> _globPatterns;
33      private final Seq<PathMatcher> _matchers;
34  
35  
36      private GlobMatcher(final Builder builder) {
37  
38          _globPatterns = builder._globPatterns;
39          _matchers = builder._matchers;
40      }
41  
42  
43      /**
44       *
45       */
46      public static GlobMatcher create(final String... globPatterns) {
47  
48          final Builder builder = builder();
49  
50          for ( final String globPattern : globPatterns ) {
51              builder.addGlobPattern(globPattern);
52          }
53  
54          return builder.build();
55      }
56  
57  
58      /**
59       * Creates a new builder with no initializations.
60       *
61       * @return A newly created <code>Builder</code> instance.
62       */
63      public static Builder builder() {
64  
65          return new Builder();
66      }
67  
68  
69      /**
70       * Creates a new builder initialized with the data from the given
71       * <code>GlobMatcher</code>.
72       *
73       * @param data Used for initializing the builder state.
74       *
75       * @return A newly created <code>Builder</code> instance.
76       */
77      public static Builder builder(final GlobMatcher data) {
78  
79          return new Builder(data);
80      }
81  
82  
83      /**
84       * Checks if the given path matches the glob pattern represented
85       * by this object.
86       *
87       * @param path The path to be checked.
88       *
89       * @return True if the given path matches our glob pattern. False
90       * otherwise.
91       */
92      @Override
93      public boolean test(final Path path) {
94  
95          final Path name = path.getFileName();
96          final Predicate<PathMatcher> isMatch = matcher -> matcher.matches(name);
97  
98          return _matchers
99                  .filter(isMatch)
100                 .headOption()
101                 .isDefined();
102     }
103 
104 
105     /**
106      * Intended for logging or debugging.
107      *
108      * @return The string representation of our glob pattern.
109      */
110     @Override
111     public String toString() {
112 
113         // This implementation is not particularly performant. Let us
114         // hope client code only uses this method for sporadic logging
115         // or debugging.
116 
117         return String.join(",", _globPatterns);
118     }
119 
120 
121 
122 
123 
124     /**
125      * A builder of <code>GlobMatcher</code> instances.
126      */
127     public static final class Builder {
128 
129 
130         private Seq<String> _globPatterns;
131         private Seq<PathMatcher> _matchers;
132 
133 
134         /**
135          *
136          */
137         /* default */ Builder() {
138 
139             _globPatterns = Array.of();
140             _matchers = Array.of();
141         }
142 
143 
144         /**
145          *
146          */
147         /* default */ Builder(final GlobMatcher globMatcher) {
148 
149             _globPatterns = globMatcher._globPatterns;
150             _matchers = globMatcher._matchers;
151         }
152 
153 
154         /**
155          *
156          *
157          * @throws PatternSyntaxException If the given glob pattern is
158          * invalid.
159          */
160         public Builder addGlobPattern(final String globPattern) {
161 
162             final PathMatcher matcher = DEFAULT_FILESYSTEM.getPathMatcher("glob:" + globPattern);
163 
164             _globPatterns = _globPatterns.append(globPattern);
165             _matchers = _matchers.append(matcher);
166 
167             return this;
168         }
169 
170 
171         /**
172          *
173          */
174         public Builder addGlobMatcher(final GlobMatcher globMatcher) {
175 
176             _globPatterns = _globPatterns.appendAll(globMatcher._globPatterns);
177             _matchers = _matchers.appendAll(globMatcher._matchers);
178 
179             return this;
180         }
181 
182 
183         /**
184          *
185          */
186         public GlobMatcher build() {
187 
188             return new GlobMatcher(this);
189         }
190 
191 
192     }
193 
194 
195 }