Project Report: fawkez

Packagesummary org.jcoderz.commons.tracing

org.jcoderz.commons.tracing.AspectPattern

LineHitsNoteSource
1  /*
2   * $Id: ArraysUtil.java 1011 2008-06-16 17:57:36Z amandel $
3   *
4   * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions are
8   * met:
9   *
10   *    * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *    * Redistributions in binary form must reproduce the above
13   *      copyright notice, this list of conditions and the following
14   *      disclaimer in the documentation and/or other materials
15   *      provided with the distribution.
16   *    * Neither the name of the jCoderZ.org Project nor the names of
17   *      its contributors may be used to endorse or promote products
18   *      derived from this software without specific prior written
19   *      permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   */
33  package org.jcoderz.commons.tracing;
34  
35  
36  import java.util.Arrays;
37  import java.util.Iterator;
38  import java.util.regex.Pattern;
39  
40  import org.jcoderz.commons.ArgumentMalformedException;
41  import org.objectweb.asm.Opcodes;
42  import org.objectweb.asm.Type;
43  
44  
45  /**
46   * This class allows to match aspectJ like patterns with the java
47   * internal class representation.
48   * <p>
49   * The following limitations / specialties should be considered:
50   * <ul>
51   * <li>the '+' is not supported so you can not check for classes
52   * implementing a certain interface.</li>
53   * <li><code>throws</code> is not supported as a part of the matching
54   * signature.</li>
55   * <li>The pattern is based on the information you can find at <a
56   * href="http://aspectwerkz.codehaus.org/definition_issues.html">
57   * aspectwerkz</a></li>
58   * <li>The method name <code>new</code> can be used to refer to the
59   * constructor (<code>&lt;init></code>) and to the class (
60   * <code>&lt;clinit></code>) initialization.</li>
61   * </ul>
62 (1) * TODO: Javadoc 
63 (2) * TODO: Support '+' for inheritance 
64   * 
65   * @author Andreas Mandel
66   */
67  public class AspectPattern
68  {
69      private final String mPattern;
70  
71      private final String mClassRegex;
72  
73      private final String mMethodRegex;
74  
75      private String mReturnPattern;
76  
77      /** The tracer class that should be called if the pattern matches. */
78      private String mTracerClass;
79  
80      private int mModifiers;
81  
82      private Pattern mClassMatcher;
83  
84      private Pattern mMethodMatcher;
85  
86      /**
87       * Creates new aspect pattern matcher. The input is translated into
88       * regular expressions which are compiled and stored in this
89       * AspectPattern.
90       * 
91       * @param in the aspectJ like pattern.
92       */
93      public AspectPattern (String in)
94100     {
95100         mPattern = in;
96100         int pos = 0;
97100         pos = getTracerClass(0);
98100         pos = getModifiers(pos);
99100         pos = getReturnType(pos);
100100         final int paraPos = mPattern.indexOf('(', pos);
101100         final int methodPos = mPattern.substring(pos, paraPos).lastIndexOf('.')
102              + pos;
103 (3)        // TODO Support +!
104100         mClassRegex = convertToPattern(mPattern.substring(pos, methodPos));
105100         final String methodName = convertToMethod(mPattern.substring(
106              methodPos + 1, paraPos));
107100         final String arguments = convertToArgumets(mPattern.substring(
108              paraPos + 1, mPattern.length() - 1));
109100(4)        mMethodRegex = methodName + "\\(" + arguments + "\\)" + mReturnPattern;
110100     }
111  
112      /**
113       * Parse the optional name of the tracer class to be used.
114       * As a side effect {@link #mTracerClass} is set.
115       * @param i the pos where to start parsing
116       * @return the pos after the tracer class name.
117       */
118      private int getTracerClass (int i)
119      {
120100         int pos = i;
121100         int end = i;
122          while (pos < mPattern.length()
123100             && Character.isWhitespace(mPattern.charAt(pos)))
124          {
1250             pos++;
126          }
127100         if (pos < mPattern.length()
128              && mPattern.charAt(pos) == '(')
129          {
1300             end = mPattern.indexOf(')', pos);
1310             if (end == -1)
132              {
1330(5)                throw new ArgumentMalformedException(
134                      "pattern", mPattern,
135                      "Opening '(' for tracing class name is not closed.");
136              }
1370             mTracerClass = mPattern.substring(pos + 1, end);
1380             end += 1;
139              while (end < mPattern.length()
1400                 && Character.isWhitespace(mPattern.charAt(end)))
141              {
1420                 end++;
143              }
144          }
145100         return end;
146      }
147  
148      /**
149       * Tests if the given class with the given access flags matches this
150       * pattern.
151       * 
152       * @param acc the access flags.
153       * @param className name of the class in internal representation.
154       * @param arguments argument string in internal representation.
155       * @return true if the given parameters match this matcher.
156       */
157      public boolean matches (int acc, String className, String arguments)
158      {
159100         return ((acc & mModifiers) == mModifiers
160              && className.matches(mClassRegex)
161              && arguments.matches(mMethodRegex));
162      }
163  
164      /**
165       * @param substring
166    * @return
167       */
168      private String convertToArgumets (String substring)
169      {
170100         final String[] args = substring.split(",");
171100         final StringBuffer pattern = new StringBuffer();
172100         final Iterator i = Arrays.asList(args).iterator();
173100         while (i.hasNext())
174          {
175100             final String arg = (String) i.next();
176100             if (!org.jcoderz.commons.util.StringUtil.isEmptyOrNull(arg))
177              {
178100                 final Type argType = tryBasicType(arg);
179100                 if (argType == null)
180                  {
181100                     if ("*".equals(arg))
182                      {
183100                         pattern.append("\\[*([VZCBSIFJD]|L[^;]+;)");
184                      }
185100                     else if ("..".equals(arg))
186                      {
187100                         pattern.append(".*");
188                      }
189                      else
190                      {
191100                         pattern.append(convertToArgumentPattern(arg));
192                      }
193                  }
194                  else
195                  {
196100                     pattern.append(argType.getDescriptor());
197                  }
198              }
199100         }
200100         return pattern.toString();
201      }
202  
203      /**
204       * @param method
205    * @return
206       */
207      private String convertToMethod (String method)
208      {
209          String result;
210          // NEW!!!
211100         if ("new".equals(method))
212          {
2130             if ((mModifiers & Opcodes.ACC_STATIC) != 0)
214              {
2150                 result = "<init>";
216              }
217              else
218              {
2190                 result = "<clinit>";
220              }
221          }
222          else
223          {
224100             result = method.replaceAll("\\*", ".*");
225          }
226100         return result;
227      }
228  
229      /**
230       * @param pos
231    * @return
232       */
233      private int getReturnType (int pos)
234      {
235100         final int result = (mPattern + " ").indexOf(' ', pos) + 1;
236100         final String typeString = mPattern.substring(pos, result - 1);
237100         final Type returnType = tryBasicType(typeString);
238100         if (returnType == null)
239          {
240100             mReturnPattern = convertToArgumentPattern(typeString);
241          }
242          else
243          {
244100             mReturnPattern = returnType.getDescriptor();
245          }
246100         return result;
247      }
248  
249      /**
250       * @param typeString
251    * @return
252       */
253      private String convertToPattern (String typeString)
254      {
255100         String resultPattern = typeString;
256100         if (org.jcoderz.commons.util.StringUtil.isNullOrEmpty(typeString))
257          {
2580             resultPattern = "";
259          }
260100         else if ("*".equals(typeString))
261          {
262100             resultPattern = "[^/]*"; // any
263          }
264          else
265          {
266100             resultPattern = resultPattern.replaceAll("\\.", "/");
267100             resultPattern = resultPattern.replaceAll("\\*", "[^\\/]*");
268100             resultPattern = resultPattern.replaceAll("//", ".*");
269              // NO 'java.lang / java.util Magic if package is given or
270              // wildcards are used.
271100             if (resultPattern.indexOf('/') < 0
272                  && resultPattern.indexOf('*') < 0)
273              {
274100                 final StringBuffer pattern = new StringBuffer("(java/util/");
275100                 pattern.append(resultPattern);
276100(6)                pattern.append('|');
277100                 pattern.append("java/lang/");
278100                 pattern.append(resultPattern);
279100                 pattern.append('|');
280100                 pattern.append(resultPattern);
281100                 pattern.append(')');
282100                 resultPattern = pattern.toString();
283              }
284          }
285100         return resultPattern;
286      }
287  
288      /**
289       * @param typeString
290    * @return
291       */
292      private String convertToArgumentPattern (String typeString)
293      {
294100         String resultPattern = typeString;
295100         if (org.jcoderz.commons.util.StringUtil.isNullOrEmpty(typeString))
296          {
2970             resultPattern = "";
298          }
299100         else if ("*".equals(typeString))
300          {
301100             resultPattern = "\\[*([VZCBSIFJD]|L[^;]+;)";
302          }
303          else
304          {
305100             String arrayPrefix = "";
306              // take care for arrays!!!
307100             while (resultPattern.endsWith("[]"))
308              {
309100(7)(8)                arrayPrefix += "\\[";
310100                 resultPattern 
311                      = resultPattern.substring(0, resultPattern.length()
312                          - "[]".length());
313              }
314100             resultPattern = resultPattern.replaceAll("\\.", "/");
315100             resultPattern = resultPattern.replaceAll("\\*", "[^\\/]*");
316100             resultPattern = resultPattern.replaceAll("//", ".*");
317              // NO 'java.lang / java.util Magic if package is given or
318              // wildcards are used.
319100             if (resultPattern.indexOf('/') >= 0
320                  || resultPattern.indexOf('*') >= 0)
321              {
3220                 final StringBuffer pattern = new StringBuffer(arrayPrefix);
3230                 pattern.append('L');
3240                 pattern.append(resultPattern);
3250                 pattern.append(';');
3260                 resultPattern = pattern.toString();
3270             }
328              else
329              {
330100                 final StringBuffer pattern = new StringBuffer("(");
331100                 pattern.append(arrayPrefix);
332100                 pattern.append("Ljava/util/");
333100                 pattern.append(resultPattern);
334100(9)                pattern.append(';');
335100                 pattern.append('|');
336100                 pattern.append(arrayPrefix);
337100                 pattern.append("Ljava/lang/");
338100                 pattern.append(resultPattern);
339100(10)                pattern.append(';');
340100                 pattern.append('|');
341100                 pattern.append(arrayPrefix);
342100                 pattern.append('L');
343100                 pattern.append(resultPattern);
344100                 pattern.append(";)");
345100                 resultPattern = pattern.toString();
346              }
347          }
348100         return resultPattern;
349      }
350  
351      /**
352       * @param typeString
353    * @return
354       */
355      private Type tryBasicType (String typeString)
356      {
357100         final StringBuffer type = new StringBuffer();
358100         String in = typeString;
359100         while (in.endsWith("[]"))
360          {
361100             type.append('[');
362100             in = in.substring(0, in.length() - "[]".length());
363          }
364100         if ("int".equals(in))
365          {
366100             type.append('I');
367          }
368100         else if ("void".equals(in))
369          {
370100             type.append('V');
371          }
372100         else if ("boolean".equals(in))
373          {
3740             type.append('Z');
375          }
376100         else if ("char".equals(in))
377          {
3780             type.append('C');
379          }
380100         else if ("short".equals(in))
381          {
3820             type.append('S');
383          }
384100         else if ("float".equals(in))
385          {
3860             type.append('F');
387          }
388100         else if ("long".equals(in))
389          {
3900             type.append('J');
391          }
392100         else if ("double".equals(in))
393          {
3940             type.append('D');
395          }
396          else
397          {
398100             type.setLength(0);
399          }
400100         Type resultType = null;
401100         if (type.length() != 0)
402          {
403100             resultType = Type.getType(type.toString());
404100             if (resultType.getSort() == Type.OBJECT)
405              {
4060                 resultType = null;
407              }
408          }
409100         return resultType;
410      }
411  
412      /**
413       * @param pos
414    * @return
415       */
416      private int getModifiers (int pos)
417      {
418100         int result = pos;
419          int oldResult;
420          do
421          {
422100             oldResult = result;
423100             result = checkModifier("public ", Opcodes.ACC_PUBLIC, result);
424100             result = checkModifier("private ", Opcodes.ACC_PRIVATE, result);
425100             result = checkModifier("protected ", Opcodes.ACC_PROTECTED, result);
426100             result = checkModifier("static ", Opcodes.ACC_STATIC, result);
427100             result = checkModifier("final ", Opcodes.ACC_FINAL, result);
428100             result 
429                  = checkModifier(
430                      "synchronized ", Opcodes.ACC_SYNCHRONIZED, result);
431100             result 
432                  = checkModifier(
433                      "deprecated ", Opcodes.ACC_DEPRECATED, result);
434          }
435100         while (result != oldResult);
436100         return result;
437      }
438  
439      /**
440       * @param modifier
441    * @param acc
442    * @param pos
443    * @return
444       */
445      private int checkModifier (String modifier, int acc, int pos)
446      {
447100         int result = pos;
448100         if (mPattern.startsWith(modifier, pos))
449          {
450100             mModifiers |= acc;
451100             result += modifier.length();
452          }
453100         return result;
454      }
455  
456 (11)    public int getModifiers ()
457      {
458100         return mModifiers;
459      }
460  
461 (12)    public String getMethodPattern ()
462      {
463100         return mMethodRegex;
464      }
465  
466 (13)    public String getClassRegex ()
467      {
468100         return mClassRegex;
469      }
470  
471      // HOWTO Handle inheritance?
472      /**
473       * @param internalClassname
474    * @return
475       */
476 (14)(15)(16)    public boolean matchClass (String internalClassname)
477      {
478100         if (mClassMatcher == null)
479          {
480100             mClassMatcher = Pattern.compile(mClassRegex);
481          }
482100         return mClassMatcher.matcher(internalClassname).matches();
483      }
484  
485      /**
486       * @param methodDesc
487    * @return
488       */
489 (17)(18)(19)    public boolean matchMethod (String methodDesc)
490      {
491100         if (mMethodMatcher == null)
492          {
493100             mMethodMatcher = Pattern.compile(mMethodRegex);
494          }
495100         return mMethodMatcher.matcher(methodDesc).matches();
496      }
497  
498      /** {@inheritDoc} */
499      public String toString ()
500      {
501100         return mPattern + " = '" + AsmUtil.toString(mModifiers) + " "
502              + mClassRegex + "#" + mMethodRegex + "'";
503      }
504  
505      /**
506       * @param access
507    * @return
508       */
509 (20)(21)(22)    public boolean matchAccess (int access)
510      {
511100         return (access & mModifiers) == mModifiers;
512      }
513  
514      String getMethodRegex ()
515      {
516100         return mMethodRegex;
517      }
518  
519 (23)    public String getTracerClass ()
520      {
5210         return mTracerClass;
522      }
523  }

Findings in this File

i (1) 62 : 0 Comment matches to-do format '(TODO|FIXME|CHECKME)'.
i (2) 63 : 0 Comment matches to-do format '(TODO|FIXME|CHECKME)'.
i (3) 103 : 0 Comment matches to-do format '(TODO|FIXME|CHECKME)'.
w (4) 109 : 0 class org.jcoderz.commons.tracing.AspectPattern defines fields that are used only as locals
i (5) 133 : 0 method org.jcoderz.commons.tracing.AspectPattern.getTracerClass(int) throws exception with static message string
i (6) 276 : 31 StringBuffer.append is called 2 consecutive times with literal Strings. Use a single append with a single String.
w (7) 309 : 0 Method org.jcoderz.commons.tracing.AspectPattern.convertToArgumentPattern(String) concatenates strings using + in a loop
c (8) 309 : 29 Prefer StringBuffer over += for concatenating strings
i (9) 334 : 31 StringBuffer.append is called 2 consecutive times with literal Strings. Use a single append with a single String.
i (10) 339 : 31 StringBuffer.append is called 2 consecutive times with literal Strings. Use a single append with a single String.
c (11) 456 : 5 Missing a Javadoc comment.
c (12) 461 : 5 Missing a Javadoc comment.
c (13) 466 : 5 Missing a Javadoc comment.
c (14) 476 : 0 Expected an @return tag.
c (15) 476 : 39 Expected @param tag for 'internalClassname'.
d (16) 476 : 0 @return tag has no arguments.
c (17) 489 : 0 Expected an @return tag.
c (18) 489 : 40 Expected @param tag for 'methodDesc'.
d (19) 489 : 0 @return tag has no arguments.
c (20) 509 : 0 Expected an @return tag.
c (21) 509 : 37 Expected @param tag for 'access'.
d (22) 509 : 0 @return tag has no arguments.
c (23) 519 : 5 Missing a Javadoc comment.