Coverage Report - th.co.edge.jseq.ConstructorFilter
 
Classes in this File Line Coverage Branch Coverage Complexity
ConstructorFilter
0%
0/23
0%
0/16
0
 
 1  
 /*
 2  
  * Copyright (c) 2003-2008, by Henrik Arro and Contributors
 3  
  *
 4  
  * This file is part of JSeq, a tool to automatically create
 5  
  * sequence diagrams by tracing program execution.
 6  
  *
 7  
  * See <http://jseq.sourceforge.net> for more information.
 8  
  *
 9  
  * JSeq is free software: you can redistribute it and/or modify
 10  
  * it under the terms of the GNU Lesser General Public License as
 11  
  * published by the Free Software Foundation, either version 3 of
 12  
  * the License, or (at your option) any later version.
 13  
  *
 14  
  * JSeq is distributed in the hope that it will be useful,
 15  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 17  
  * GNU Lesser General Public License for more details.
 18  
  *
 19  
  * You should have received a copy of the GNU Lesser General Public License
 20  
  * along with JSeq. If not, see <http://www.gnu.org/licenses/>.
 21  
  */
 22  
 
 23  
 package th.co.edge.jseq;
 24  
 
 25  
 import com.sun.jdi.Method;
 26  
 
 27  
 import th.co.edge.jseq.ActivationList.Filter;
 28  
 
 29  
 /**
 30  
  * A <code>Filter</code> that accepts all methods, except constructors that
 31  
  * are either synthetic (automatically created by the compiler), or are calls to
 32  
  * <code>super</code>.
 33  
  *
 34  
  * <p>
 35  
  * The reason that this filter was created was to remove "unnecessary" calls to
 36  
  * <code>&lt;init&gt;</code> from the sequence diagrams. Since the sequence
 37  
  * diagrams generated by JSeq are class-based, not instance-based (i.e., each
 38  
  * lifeline belongs to a class, not to a specific instance), and since the class
 39  
  * of the instance being called is used (not the declaring class), calls to
 40  
  * synthetic constructors or to the super constructor would be represented as
 41  
  * one or several calls to <code>&lt;init&gt;</code> back to the same class.
 42  
  * This was deemed more confusing than helpful.
 43  
  *
 44  
  * <p>
 45  
  * In order to determine if a call is a call to a super-class constructor, this
 46  
  * filter needs access to a <code>ClassLoader</code>. When running JSeq
 47  
  * stand-alone, this is not a problem, but when attaching to a running process,
 48  
  * JSeq should have the same classpath as that process. If not, the only effect
 49  
  * is that the "unnecessary" constructor calls are included in the diagram, so
 50  
  * failure to set up the correct classpath when attaching to a process is far
 51  
  * from catastrophic.
 52  
  *
 53  
  * <p>
 54  
  * This filter was created after Jacek Ratzinger supplied his patch (<a
 55  
  * href="https://sourceforge.net/tracker/index.php?func=detail&aid=2027500&group_id=230519&atid=1080393"
 56  
  * target="new">SourceForge issue 2027500</a>) since that change made calls to
 57  
  * the super-class constructor look as calls back to the same class. In the
 58  
  * process it also turned out that private nested classes use a synthetic
 59  
  * constructor that need not be shown in the generated sequence diagrams.
 60  
  */
 61  
 public class ConstructorFilter implements Filter {
 62  
     private ClassLoader classLoader;
 63  
 
 64  
     /**
 65  
      * Creates a new <code>ConstructorFilter</code> that uses the given
 66  
      * <code>ClassLoader</code> to determine if a call is to a super-class
 67  
      * constructor.
 68  
      *
 69  
      * @param classLoader
 70  
      *            a <code>ClassLoader</code> that should match that of the
 71  
      *            process being traced
 72  
      */
 73  0
     public ConstructorFilter(ClassLoader classLoader) {
 74  0
         this.classLoader = classLoader;
 75  0
     }
 76  
 
 77  
     /**
 78  
      * Returns <code>true</code> for all <code>Activation</code>s, except
 79  
      * calls to synthetic constructors and calls to super-class constructors.
 80  
      *
 81  
      * @param activation
 82  
      *            the <code>Activation</code> to check
 83  
      *
 84  
      * @return <code>false</code> if <code>activation</code> represents a
 85  
      *         call to a synthetic constructor or a call to a super-class
 86  
      *         constructor, <code>true</code> otherwise
 87  
      */
 88  
     @Override
 89  
     public boolean accept(Activation activation) {
 90  0
         boolean accepted = true;
 91  0
         Method method = activation.getMethod();
 92  0
         if (method.isConstructor() && activation.getParent() != null) {
 93  0
             Activation parentActivation = activation.getParent();
 94  0
             Method parentMethod = parentActivation.getMethod();
 95  0
             if (parentMethod != null && parentMethod.isConstructor()) {
 96  0
                 if (parentMethod.isSynthetic()) {
 97  0
                     accepted = false;
 98  0
                 } else if (isDeclaredInSuperclass(method, parentMethod)) {
 99  0
                     accepted = false;
 100  
                 }
 101  
             }
 102  
         }
 103  0
         return accepted;
 104  
     }
 105  
 
 106  
     /**
 107  
      * Returns <code>true</code> if the method <code>m1</code> is declared
 108  
      * in a superclass to the class that declares the method <code>m2</code>.
 109  
      *
 110  
      * @param m1
 111  
      *            method from superclass?
 112  
      * @param m2
 113  
      *            method from subclass?
 114  
      *
 115  
      * @return <code>true</code> if <code>m1</code> is declared in a
 116  
      *         superclass to the class where <code>m2</code> is declared
 117  
      */
 118  
     private boolean isDeclaredInSuperclass(Method m1, Method m2) {
 119  0
         boolean fromSuperclass = false;
 120  
         try {
 121  0
             Class<?> c1 = classLoader.loadClass(m1.declaringType().name());
 122  0
             Class<?> c2 = classLoader.loadClass(m2.declaringType().name());
 123  0
             if (c1.isAssignableFrom(c2) && !c1.equals(c2)) {
 124  0
                 fromSuperclass = true;
 125  
             }
 126  0
         } catch (Exception e) {
 127  0
             System.err.println(e);
 128  0
         }
 129  0
         return fromSuperclass;
 130  
     }
 131  
 }