1 /***
2 * Copyright 2007 the original author or authors.
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 * For more information visit
11 * http://72miles.com and
12 * http://architecturerules.googlecode.com/svn/docs/index.html
13 */
14
15 package com.seventytwomiles.architecturerules.domain;
16
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20
21 import static java.lang.String.format;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25
26
27 /***
28 * <p>A java package. This class wraps the java package to give it
29 * functionality, such as the ability to check and see if it matches another
30 * package.</p>
31 *
32 * @author mikenereson
33 */
34 public class JPackage {
35
36
37 private static final Log log
38 = LogFactory.getLog(JPackage.class);
39
40 /***
41 * <p>All of the symbols or characters that represent a wildcard.</p>
42 */
43 private static final char[] WILDCHARS = new char[]{'*'};
44
45 /***
46 * <p>period separated path to package such as <samp>com.seventeytwomiles.architecturerules.domain</samp>.</p>
47 *
48 * @parameter path String
49 */
50 private String path;
51
52
53 /***
54 * <p>Constructs a new <code>JPackage</code></p>
55 */
56 public JPackage() {
57 }
58
59
60 /***
61 * <p>Constructs a new <code>JPackage</code> with the given
62 * <tt>path</tt></p>
63 *
64 * @param path String to set for {@link #path}
65 */
66 public JPackage(final String path) {
67
68 setPath(path);
69 }
70
71
72 /***
73 * <p>Getter for property {@link #path}.</p>
74 *
75 * @return Value for property <tt>path</tt>.
76 */
77 public String getPath() {
78
79 return path;
80 }
81
82
83 /***
84 * <p>Setter for property {@link #path}</p>
85 *
86 * @param path Value to set for property <tt>path</tt>
87 */
88 public void setPath(final String path) {
89
90 this.path = path;
91 }
92
93
94 public boolean equals(final Object o) {
95
96 if (this == o)
97 return true;
98
99 if (!(o instanceof JPackage))
100 return false;
101
102 final JPackage that = (JPackage) o;
103
104 if (path != null
105 ? !path.equals(that.getPath())
106 : that.getPath() != null) {
107
108 return false;
109 }
110
111 return true;
112 }
113
114
115 public int hashCode() {
116
117 return (path != null ? path.hashCode() : 0);
118 }
119
120
121 /***
122 * @see Object#toString()
123 */
124 public String toString() {
125
126 return this.path;
127 }
128
129
130 /***
131 * <p>Determines if a given <code>JPackage</code> or <code>String</code> is
132 * represented by this <code>JPackage</code>.</p>
133 *
134 * <p>If given Object is empty String then <tt>false<tt><</p>
135 *
136 * @param that a String or JPackage
137 * @return boolean <tt>true</tt> when a perfect match is found or when the
138 * wildcards match.
139 */
140 public boolean matches(final Object that) {
141
142 if (!(that instanceof String)
143 && !(that instanceof JPackage)) {
144
145 return false;
146 }
147
148 if (that.equals(""))
149 return false;
150
151
152 if (hasWildcards()) {
153
154 return regExMatch(that);
155
156 } else {
157
158 return prefectMatch(that);
159 }
160 }
161
162
163 /***
164 * <p>Determines if this <code>JPackage</code> uses wildcards to match more
165 * than one package.</p>
166 *
167 * @return boolean <tt>true</tt> when <tt>path</tt> contains any of the
168 * {@link #WILDCHARS}.
169 */
170 private boolean hasWildcards() {
171
172 for (final char wildChar : WILDCHARS)
173 if (this.path.contains(String.valueOf(wildChar)))
174 return true;
175
176 return false;
177 }
178
179
180 /***
181 * <p>Manipulates the <tt>path</tt> value to add Regular Expression support
182 * then attempts to match the Reg Ex against the given <tt>Object</tt>.</p>
183 *
184 * <p>This supports <dl> <dt>terminating package</dt> <dd>1.2.*</dd>
185 * <dt>terminating package or sub package description</dt> <dd>1.2..*</dd>
186 * <dt>internal package</dt> <dd>1.*.2</dd> <dt>internal package or sub
187 * package</dt> <dd>1.*..4</dd> <dt>internal and terminating</dt>
188 * <dd>1.*.3.*</dd> <dd>1.*.3..*</dd><dd>1..*.5.*</dd> </dl></p>
189 *
190 *
191 * <p>TODO: This does not support the single character <tt>*</tt> yet.</p>
192 *
193 * @param that <code>Object</code> of type <code>String</code> or
194 * <code>JPackage</code>
195 * @return boolean <tt>true</tt> when the given <tt>Object</tt> is a
196 * supported type, and then regular expression that is constructed
197 * matches.
198 */
199 private boolean regExMatch(final Object that) {
200
201 /***
202 * TODO: code support for path = "*"
203 * TODO: then Update javadoc
204 */
205 final String regex = this.path
206
207 .replaceAll("//.", "////.")
208
209 .replaceAll("////.////.////*", "////.//[A-Za-z_0-9.]")
210
211 .replaceAll("//.//*", "//.[A-Za-z_0-9]*");
212
213 final Pattern pattern = Pattern.compile(regex);
214 final Matcher matcher;
215
216 final boolean matched;
217
218 if (that instanceof String) {
219
220 final String thatPackage = (String) that;
221 matcher = pattern.matcher(thatPackage);
222
223 matched = matcher.matches();
224
225 } else if (that instanceof JPackage) {
226
227 final JPackage thatPackage = (JPackage) that;
228 matcher = pattern.matcher(thatPackage.getPath());
229
230 matched = matcher.matches();
231
232 } else {
233
234 matched = false;
235 }
236
237 if (matched)
238 log.debug(format("matched %s to %s", this.path, that));
239
240 return matched;
241 }
242
243
244 /***
245 * <p>Matches by String equals against a String or JPackage</p>
246 *
247 * @param that <code>Object</code> of type <code>String</code> or
248 * <code>JPackage</code>
249 * @return <tt>true</tt> when the given <tt>Object</tt> is a supported type,
250 * and an exact match to this <code>JPackage</code>.
251 */
252 private boolean prefectMatch(final Object that) {
253
254 if (that instanceof String) {
255
256 final String thatPackage = (String) that;
257 return this.path.equals(thatPackage);
258 }
259
260 if (that instanceof JPackage) {
261
262 final JPackage thatPackage = (JPackage) that;
263 return this.path.equals(thatPackage.getPath());
264 }
265
266 return false;
267 }
268 }