1 /***************************************************************************************
2 * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
3 * http://aspectwerkz.codehaus.org *
4 * ---------------------------------------------------------------------------------- *
5 * The software in this package is published under the terms of the LGPL license *
6 * a copy of which has been included with this distribution in the license.txt file. *
7 **************************************************************************************/
8 package org.codehaus.aspectwerkz.expression.regexp;
9
10 import org.codehaus.aspectwerkz.expression.ExpressionException;
11 import org.codehaus.aspectwerkz.expression.SubtypePatternType;
12 import org.codehaus.aspectwerkz.util.Strings;
13 import org.codehaus.aspectwerkz.reflect.ClassInfo;
14 import org.codehaus.aspectwerkz.proxy.Proxy;
15
16 import java.io.ObjectInputStream;
17
18 /***
19 * Implements the regular expression pattern matcher for types.
20 *
21 * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
22 */
23 public class TypePattern extends Pattern {
24
25 /***
26 * The fully qualified type name.
27 */
28 protected transient com.karneim.util.collection.regex.Pattern m_typeNamePattern;
29
30 /***
31 * The pattern as a string.
32 */
33 protected String m_pattern;
34
35 /***
36 * The subtype pattern type.
37 */
38 private SubtypePatternType m_subtypePatternType;
39
40 /***
41 * Private constructor.
42 *
43 * @param pattern the pattern
44 * @param subtypePatternType the subtype pattern type
45 */
46 TypePattern(final String pattern, final SubtypePatternType subtypePatternType) {
47 m_pattern = pattern;
48 m_subtypePatternType = subtypePatternType;
49 escape(m_pattern);
50 }
51
52 /***
53 * Matches a type name.
54 *
55 * @param typeName the name of the type
56 * @return true if we have a matche
57 */
58 public boolean matches(String typeName) {
59 int awProxySuffixStart = typeName.indexOf(Proxy.PROXY_SUFFIX_START);
60 if (awProxySuffixStart > 0) {
61 typeName = typeName.substring(0, awProxySuffixStart);
62 } else {
63 int cglibFastClassSuffixStarg = typeName.indexOf("$$FastClassByCGLIB$$");
64 if (cglibFastClassSuffixStarg > 0) {
65
66 return false;
67 }
68 int cglibEnhancerSuffixStart = typeName.indexOf("$$EnhancerByCGLIB$$");
69 if (cglibEnhancerSuffixStart > 0) {
70 typeName = typeName.substring(0, cglibEnhancerSuffixStart);
71 }
72 }
73 if (typeName == null) {
74 return false;
75 }
76 if (typeName.equals("")) {
77 return false;
78 }
79 return m_typeNamePattern.contains(typeName);
80 }
81
82 /***
83 * Matches a type.
84 *
85 * @param classInfo the info of the class
86 * @return
87 */
88 public boolean matchType(final ClassInfo classInfo) {
89 SubtypePatternType type = getSubtypePatternType();
90 if (type.equals(SubtypePatternType.MATCH_ON_ALL_METHODS)) {
91 return matchSuperClasses(classInfo);
92 } else if (type.equals(SubtypePatternType.MATCH_ON_BASE_TYPE_METHODS_ONLY)) {
93
94
95 return matchSuperClasses(classInfo);
96 } else {
97 return matches(classInfo.getName());
98 }
99 }
100
101 /***
102 * Tries to finds a parse at some superclass in the hierarchy. <p/>Only checks for a class parse to allow early
103 * filtering. <p/>Recursive.
104 *
105 * @param classInfo the class info
106 * @return boolean
107 */
108 public boolean matchSuperClasses(final ClassInfo classInfo) {
109 if ((classInfo == null)) {
110 return false;
111 }
112
113
114 if (matches(classInfo.getName())) {
115 return true;
116 } else {
117
118 if (matchInterfaces(classInfo.getInterfaces(), classInfo)) {
119 return true;
120 }
121
122
123 return matchSuperClasses(classInfo.getSuperclass());
124 }
125 }
126
127 /***
128 * Tries to finds a parse at some interface in the hierarchy. <p/>Only checks for a class parse to allow early
129 * filtering. <p/>Recursive.
130 *
131 * @param interfaces the interfaces
132 * @param classInfo the class info
133 * @return boolean
134 */
135 public boolean matchInterfaces(final ClassInfo[] interfaces, final ClassInfo classInfo) {
136 if ((interfaces.length == 0) || (classInfo == null)) {
137 return false;
138 }
139 for (int i = 0; i < interfaces.length; i++) {
140 ClassInfo anInterface = interfaces[i];
141 if (matches(anInterface.getName())) {
142 return true;
143 } else {
144 if (matchInterfaces(anInterface.getInterfaces(), classInfo)) {
145 return true;
146 } else {
147 continue;
148 }
149 }
150 }
151 return false;
152 }
153
154 /***
155 * Returns the subtype pattern type
156 *
157 * @return boolean
158 */
159 public SubtypePatternType getSubtypePatternType() {
160 return m_subtypePatternType;
161 }
162
163 /***
164 * Checks if the pattern matches all types.
165 *
166 * @return boolean
167 */
168 public boolean isEagerWildCard() {
169 return m_pattern.equals(EAGER_WILDCARD);
170 }
171
172 /***
173 * Returns the pattern as a string.
174 *
175 * @return the pattern
176 */
177 public String getPattern() {
178 return m_pattern;
179 }
180
181 /***
182 * Escapes the type pattern.
183 *
184 * @param pattern the method pattern
185 */
186 protected void escape(final String pattern) {
187 String typeName = pattern;
188 if (ABBREVIATIONS.containsKey(pattern)) {
189 typeName = (String) ABBREVIATIONS.get(pattern);
190 }
191 try {
192 if (typeName.equals(REGULAR_WILDCARD) || typeName.equals(EAGER_WILDCARD)) {
193 typeName = "[a-zA-Z0-9_$.//[//]]+";
194 } else {
195
196 typeName = Strings.replaceSubString(typeName, "[", "//[");
197 typeName = Strings.replaceSubString(typeName, "]", "//]");
198 typeName = Strings.replaceSubString(typeName, "..", "[a-zA-Z0-9_$.]+");
199 typeName = Strings.replaceSubString(typeName, ".", "//.");
200 typeName = Strings.replaceSubString(typeName, "*", "[a-zA-Z0-9_$//[//]]*");
201 }
202 m_typeNamePattern = new com.karneim.util.collection.regex.Pattern(typeName);
203 } catch (Throwable e) {
204 throw new ExpressionException("type pattern is not well formed: " + pattern, e);
205 }
206 }
207
208 /***
209 * Provides custom deserialization.
210 *
211 * @param stream the object input stream containing the serialized object
212 * @throws Exception in case of failure
213 */
214 private void readObject(final ObjectInputStream stream) throws Exception {
215 ObjectInputStream.GetField fields = stream.readFields();
216 m_pattern = (String) fields.get("m_pattern", null);
217 escape(m_pattern);
218 }
219
220 public int hashCode() {
221 int result = 17;
222 result = (37 * result) + hashCodeOrZeroIfNull(m_pattern);
223 result = (37 * result) + hashCodeOrZeroIfNull(m_typeNamePattern);
224 return result;
225 }
226
227 protected static int hashCodeOrZeroIfNull(final Object o) {
228 if (null == o) {
229 return 19;
230 }
231 return o.hashCode();
232 }
233
234 public boolean equals(final Object o) {
235 if (this == o) {
236 return true;
237 }
238 if (!(o instanceof TypePattern)) {
239 return false;
240 }
241 final TypePattern obj = (TypePattern) o;
242 return areEqualsOrBothNull(obj.m_pattern, this.m_pattern)
243 && areEqualsOrBothNull(obj.m_typeNamePattern, this.m_typeNamePattern);
244 }
245
246 protected static boolean areEqualsOrBothNull(final Object o1, final Object o2) {
247 if (null == o1) {
248 return (null == o2);
249 }
250 return o1.equals(o2);
251 }
252 }