View Javadoc

1   /*
2    * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.properties.spi.config.domain.key;
17  
18  import java.io.Serializable;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.apache.commons.lang.StringUtils;
23  
24  import de.smartics.properties.api.config.domain.key.ConfigurationKey;
25  import de.smartics.util.lang.Arg;
26  
27  /**
28   * Matches a path that may contain wildcards at the end of the path.
29   */
30  public final class PathMatcher implements PropertiesResourceMatcher
31  {
32    // ********************************* Fields *********************************
33  
34    // --- constants ------------------------------------------------------------
35  
36    /**
37     * The class version identifier.
38     * <p>
39     * The value of this constant is {@value}.
40     * </p>
41     */
42    private static final long serialVersionUID = 1L;
43  
44    // --- members --------------------------------------------------------------
45  
46    /**
47     * The configuration key the matcher is responsible for.
48     *
49     * @serial
50     */
51    private final ConfigurationKey<?> configurationKey;
52  
53    /**
54     * The list of matchers to consult in the given order.
55     *
56     * @serial
57     */
58    private final List<Matcher> matchers;
59  
60    // ****************************** Initializer *******************************
61  
62    // ****************************** Constructors ******************************
63  
64    /**
65     * Default constructor.
66     *
67     * @param configurationKey the configuration key the matcher is responsible
68     *          for.
69     * @param matchers the matchers to use for matching.
70     */
71    private PathMatcher(final ConfigurationKey<?> configurationKey,
72        final List<Matcher> matchers)
73    {
74      this.configurationKey = configurationKey;
75      this.matchers = matchers;
76    }
77  
78    // ****************************** Inner Classes *****************************
79  
80    /**
81     * Matcher of a single path.
82     */
83    public static final class Matcher implements Serializable
84    {
85      // ******************************** Fields ********************************
86  
87      // --- constants ----------------------------------------------------------
88  
89      /**
90       * The class version identifier.
91       * <p>
92       * The value of this constant is {@value}.
93       * </p>
94       */
95      private static final long serialVersionUID = 1L;
96  
97      // --- members ------------------------------------------------------------
98  
99      /**
100      * The path to match.
101      *
102      * @serial
103      */
104     private final String path;
105 
106     /**
107      * The flag to indicate whether {@code path} is a prefix to be match (
108      * <code>true</code>) or if it is an exact match (<code>false</code>).
109      *
110      * @serial
111      */
112     private final boolean wildcardMatch;
113 
114     // ***************************** Initializer ******************************
115 
116     // ***************************** Constructors *****************************
117 
118     /**
119      * Default constructor.
120      *
121      * @param path the path to match.
122      */
123     public Matcher(final String path)
124     {
125       this.wildcardMatch = Arg.checkNotNull("path", path).endsWith("*");
126       this.path = wildcardMatch ? StringUtils.chop(path) : path;
127     }
128 
129     // ***************************** Inner Classes ****************************
130 
131     // ******************************** Methods *******************************
132 
133     // --- init ---------------------------------------------------------------
134 
135     // --- get&set ------------------------------------------------------------
136 
137     // --- business -----------------------------------------------------------
138 
139     private boolean match(final String id)
140     {
141       final boolean match =
142           wildcardMatch ? id.startsWith(path) : id.equals(path);
143       return match;
144     }
145 
146     // --- object basics ------------------------------------------------------
147 
148     /**
149      * Returns the string representation of the object.
150      *
151      * @return the string representation of the object.
152      */
153     @Override
154     public String toString()
155     {
156       final StringBuilder buffer = new StringBuilder();
157 
158       buffer.append(path);
159 
160       if (wildcardMatch)
161       {
162         buffer.append("*");
163       }
164 
165       return buffer.toString();
166     }
167   }
168 
169   // ********************************* Methods ********************************
170 
171   // --- factories ------------------------------------------------------------
172 
173   /**
174    * Constructs an instance based on the given paths.
175    *
176    * @param configurationKey the configuration key the matcher is responsible
177    *          for.
178    * @param paths the list of paths to match. A path may end with <code>*</code>
179    *          signaling a wildcard match.
180    * @return the constructed instance.
181    */
182   public static PathMatcher forPaths(
183       final ConfigurationKey<?> configurationKey, final List<String> paths)
184   {
185     return forMatchers(configurationKey, convertToMatchers(paths));
186   }
187 
188   /**
189    * Constructs an instance based on the given matchers.
190    *
191    * @param configurationKey the configuration key the matcher is responsible
192    *          for.
193    * @param matchers the matchers to use for matching.
194    * @return the constructed instance.
195    */
196   public static PathMatcher forMatchers(
197       final ConfigurationKey<?> configurationKey, final List<Matcher> matchers)
198   {
199     return new PathMatcher(configurationKey, matchers);
200   }
201 
202   // --- init -----------------------------------------------------------------
203 
204   private static List<Matcher> convertToMatchers(final List<String> paths)
205   {
206     final List<Matcher> matchers = new ArrayList<Matcher>(paths.size());
207 
208     for (final String path : paths)
209     {
210       final Matcher matcher = new Matcher(path);
211       matchers.add(matcher);
212     }
213 
214     return matchers;
215   }
216 
217   // --- get&set --------------------------------------------------------------
218 
219   /**
220    * Returns the configuration key the matcher is responsible for.
221    *
222    * @return the configuration key the matcher is responsible for.
223    */
224   @Override
225   public ConfigurationKey<?> getConfigurationKey()
226   {
227     return configurationKey;
228   }
229 
230   // --- business -------------------------------------------------------------
231 
232   @Override
233   public boolean match(final String id)
234   {
235     for (final Matcher matcher : matchers)
236     {
237       final boolean match = matcher.match(id);
238       if (match)
239       {
240         return true;
241       }
242     }
243     return false;
244   }
245 
246   // --- object basics --------------------------------------------------------
247 
248   /**
249    * Returns the string representation of the object.
250    *
251    * @return the string representation of the object.
252    */
253   @Override
254   public String toString()
255   {
256     final StringBuilder buffer = new StringBuilder();
257 
258     buffer.append(configurationKey).append(':');
259 
260     for (final Matcher matcher : matchers)
261     {
262       buffer.append(' ').append(matcher);
263     }
264 
265     return buffer.toString();
266   }
267 }