001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.loggers.debug;
028    
029    import org.aspectj.lang.annotation.*;
030    import org.aspectj.lang.JoinPoint;
031    
032    import static
033        org.opends.server.loggers.debug.DebugLogger.DEFAULT_CONSTRUCTOR_LEVEL;
034    import static
035        org.opends.server.loggers.debug.DebugLogger.DEFAULT_ENTRY_EXIT_LEVEL;
036    import static
037        org.opends.server.loggers.debug.DebugLogger.DEFAULT_THROWN_LEVEL;
038    
039    /**
040     * An aspect for source-code tracing at the method level.
041     *
042     * One DebugLogger aspect instance exists for each Java class using tracing.
043     * Tracer must be registered with the DebugLogger.
044     *
045     * Logging is always done at a level basis, with debug log messages
046     * exceeding the trace threshold being traced, others being discarded.
047     */
048    @Aspect()
049    public class DebugAspect
050    {
051      /**
052       * Pointcut for matching static context events.
053       */
054      @Pointcut("!this(Object)")
055      private void staticContext()
056      {
057      }
058    
059      /**
060       * Pointcut for matching non static context events.
061       * @param obj The object being operated on.
062       */
063      @Pointcut("this(obj)")
064      private void nonStaticContext(Object obj)
065      {
066      }
067    
068      /**
069       * Pointcut for matching all toString() methods.
070       */
071      @Pointcut("execution(* *..toString(..))")
072      private void toStringMethod()
073      {
074      }
075    
076      /**
077       * Pointcut for matching all getMessage() methods.
078       */
079      @Pointcut("execution(String org.opends.server." +
080          "messages.MessageHandler.getMessage(..))")
081      private void getMessageMethod()
082      {
083      }
084    
085      /**
086       * Pointcut for matching the getDirectoryThreadGroup method.
087       */
088      @Pointcut("execution(public static ThreadGroup org.opends.server." +
089          "core.DirectoryServer.getDirectoryThreadGroup(..))")
090      private void getThreadGroupMethod()
091      {
092      }
093    
094      /**
095       * Pointcut for matching all getDebugProperties() methods.
096       * TODO: Make this less general. Find out if pointcut matches
097       * subclass methods.
098       */
099      @Pointcut("execution(* *..getDebugProperties(..))")
100      private void getDebugPropertiesMethod()
101      {
102      }
103    
104      /**
105       * Pointcut for matching all logging related classes.
106       */
107      @Pointcut("within(org.opends.server.loggers.*+ || " +
108        "org.opends.server.loggers.debug..*+ || " +
109        "org.opends.server.types.DebugLogLevel+ || " +
110        "org.opends.server.types.DebugLogCategory+ || " +
111        "org.opends.server.api.DebugLogPublisher+ || " +
112        "org.opends.server.util.TimeThread+ ||" +
113        "org.opends.server.util.MultiOutputStream+)")
114      private void debugRelatedClasses()
115      {
116      }
117    
118      /**
119       * Pointcut to exclude all pointcuts which should not be adviced by the
120       * debug logger.
121       */
122      @Pointcut("toStringMethod() || getMessageMethod() || " +
123          "getDebugPropertiesMethod() || debugRelatedClasses() || " +
124          "getThreadGroupMethod()")
125      private void excluded()
126      {
127      }
128    
129      /**
130       * Pointcut for matching the execution of all public methods.
131       */
132      @Pointcut("execution(!@(DebugLogger.NoDebugTracing || " +
133          "DebugLogger.NoEntryDebugTracing) public * *(..)) && " +
134          "!excluded()")
135      void tracedEntryMethod()
136      {
137      }
138    
139      /**
140       * Pointcut for matching the execution of all public methods.
141       */
142      @Pointcut("execution(!@(DebugLogger.NoDebugTracing || " +
143          "DebugLogger.NoExitDebugTracing) public * *(..)) && " +
144          "!excluded()")
145      void tracedExitMethod()
146      {
147      }
148    
149      /**
150       * Pointcut for matching the execution of all public methods.
151       */
152      @Pointcut("execution(@DebugLogger.TraceThrown public * *(..)) && " +
153          "!excluded()")
154      void tracedThrownMethod()
155      {
156      }
157    
158      /**
159       * Pointcut for matching the execution of all constructors.
160       */
161      @Pointcut("execution(!@(DebugLogger.NoDebugTracing || " +
162          "DebugLogger.NoEntryDebugTracing) public new(..)) && !excluded()")
163      void tracedEntryConstructor()
164      {
165      }
166    
167      /**
168       * Pointcut for matching the execution of all constructors.
169       */
170      @Pointcut("execution(!@(DebugLogger.NoDebugTracing || " +
171          "DebugLogger.NoExitDebugTracing) public new(..)) && !excluded()")
172      void tracedExitConstructor()
173      {
174      }
175    
176      /**
177       * Pointcut for matching only if there are publishers.
178       *
179       * @return if debug logging is enabled.
180       */
181      @Pointcut("if()")
182      public static boolean shouldTrace()
183      {
184        return DebugLogger.enabled;
185      }
186    
187      /**
188       * AspectJ Implementation.
189       *
190       * @param thisJoinPoint the JoinPoint reflection object.
191       */
192      @Before("shouldTrace() && tracedEntryConstructor()")
193      public void traceConstructor(JoinPoint thisJoinPoint)
194      {
195        String signature =
196            thisJoinPoint.getSignature().getDeclaringTypeName();
197        Object[] args = thisJoinPoint.getArgs();
198        DebugTracer tracer = DebugLogger.getTracer(signature);
199        if(tracer != null)
200        {
201          tracer.debugConstructor(
202              DEFAULT_CONSTRUCTOR_LEVEL, args);
203        }
204      }
205    
206      /**
207       * AspectJ Implementation.
208       *
209       * @param thisJoinPoint the JoinPoint reflection object.
210       * @param obj the object this method operations on.
211       */
212      @Before("shouldTrace() && tracedEntryMethod() && nonStaticContext(obj)")
213      public void traceNonStaticMethodEntry(JoinPoint thisJoinPoint, Object obj)
214      {
215        String signature =
216            thisJoinPoint.getSignature().getDeclaringTypeName();
217        Object[] args = thisJoinPoint.getArgs();
218        Object callerInstance = thisJoinPoint.getThis();
219        DebugTracer tracer = DebugLogger.getTracer(signature);
220        if(tracer != null)
221        {
222          tracer.debugMethodEntry(
223              DEFAULT_ENTRY_EXIT_LEVEL, callerInstance, args);
224        }
225      }
226    
227      /**
228       * AspectJ Implementation.
229       *
230       * @param thisJoinPoint the JoinPoint reflection object.
231       */
232      @Before("shouldTrace() && tracedEntryMethod() && staticContext()")
233      public void traceStaticMethodEntry(JoinPoint thisJoinPoint)
234      {
235        String signature =
236            thisJoinPoint.getSignature().getDeclaringTypeName();
237        Object[] args = thisJoinPoint.getArgs();
238        DebugTracer tracer = DebugLogger.getTracer(signature);
239        if(tracer != null)
240        {
241          tracer.debugStaticMethodEntry(
242              DEFAULT_ENTRY_EXIT_LEVEL, args);
243        }
244      }
245    
246      /**
247       * AspectJ Implementation.
248       *
249       * @param thisJoinPointStaticPart the JoinPoint reflection object.
250       * @param ret the return value of the method.
251       */
252      @AfterReturning(pointcut = "shouldTrace() && " +
253          "(tracedExitMethod() || tracedExitConstructor())",
254                      returning = "ret")
255      public void traceReturn(JoinPoint.StaticPart thisJoinPointStaticPart,
256                              Object ret)
257      {
258        String signature =
259            thisJoinPointStaticPart.getSignature().getDeclaringTypeName();
260        DebugTracer tracer = DebugLogger.getTracer(signature);
261        if(tracer != null)
262        {
263          tracer.debugReturn(
264              DEFAULT_ENTRY_EXIT_LEVEL, ret);
265        }
266      }
267    
268      /**
269       * AspectJ Implementation.
270       *
271       * @param thisJoinPointStaticPart the JoinPoint reflection object.
272       * @param ex the exception thrown.
273       */
274      @SuppressAjWarnings({"adviceDidNotMatch"})
275      @AfterThrowing(pointcut = "shouldTrace() && tracedThrownMethod()",
276                     throwing = "ex")
277      public void traceThrown(JoinPoint.StaticPart thisJoinPointStaticPart,
278                              Throwable ex)
279      {
280        String signature =
281            thisJoinPointStaticPart.getSignature().getDeclaringTypeName();
282        DebugTracer tracer = DebugLogger.getTracer(signature);
283        if(tracer != null)
284        {
285          tracer.debugThrown(
286              DEFAULT_THROWN_LEVEL, ex);
287        }
288      }
289    }