1 /*
   2  * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.jdi;
  26 
  27 import java.lang.ref.SoftReference;
  28 import java.util.ArrayList;
  29 import java.util.Collections;
  30 import java.util.HashSet;
  31 import java.util.Iterator;
  32 import java.util.List;
  33 import java.util.Map;
  34 import java.util.Set;
  35 
  36 import sun.jvm.hotspot.oops.InstanceKlass;
  37 
  38 import com.sun.jdi.ClassNotLoadedException;
  39 import com.sun.jdi.ClassType;
  40 import com.sun.jdi.Field;
  41 import com.sun.jdi.IncompatibleThreadStateException;
  42 import com.sun.jdi.InterfaceType;
  43 import com.sun.jdi.InvalidTypeException;
  44 import com.sun.jdi.InvocationException;
  45 import com.sun.jdi.Method;
  46 import com.sun.jdi.ObjectReference;
  47 import com.sun.jdi.ReferenceType;
  48 import com.sun.jdi.ThreadReference;
  49 import com.sun.jdi.Value;
  50 import com.sun.jdi.VirtualMachine;
  51 
  52 public class ClassTypeImpl extends ReferenceTypeImpl
  53     implements ClassType
  54 {
  55     private SoftReference interfacesCache    = null;
  56     private SoftReference allInterfacesCache = null;
  57     private SoftReference subclassesCache    = null;
  58 
  59     protected ClassTypeImpl(VirtualMachine aVm, InstanceKlass aRef) {
  60         super(aVm, aRef);
  61     }
  62 
  63     public ClassType superclass() {
  64         InstanceKlass kk = (InstanceKlass)ref().getSuper();
  65         if (kk == null) {
  66             return null;
  67         }
  68         return (ClassType) vm.referenceType(kk);
  69     }
  70 
  71     public List interfaces()  {
  72         List interfaces = (interfacesCache != null)? (List) interfacesCache.get() : null;
  73         if (interfaces == null) {
  74             checkPrepared();
  75             interfaces = Collections.unmodifiableList(getInterfaces());
  76             interfacesCache = new SoftReference(interfaces);
  77         }
  78         return interfaces;
  79     }
  80 
  81     void addInterfaces(List list) {
  82         List immediate = interfaces();
  83 
  84         HashSet hashList = new HashSet(list);
  85         hashList.addAll(immediate);
  86         list.clear();
  87         list.addAll(hashList);
  88 
  89         Iterator iter = immediate.iterator();
  90         while (iter.hasNext()) {
  91             InterfaceTypeImpl interfaze = (InterfaceTypeImpl)iter.next();
  92             interfaze.addSuperinterfaces(list);
  93         }
  94 
  95         ClassTypeImpl superclass = (ClassTypeImpl)superclass();
  96         if (superclass != null) {
  97             superclass.addInterfaces(list);
  98         }
  99     }
 100 
 101     public List allInterfaces()  {
 102         List allinterfaces = (allInterfacesCache != null)? (List) allInterfacesCache.get() : null;
 103         if (allinterfaces == null) {
 104             checkPrepared();
 105             allinterfaces = new ArrayList();
 106             addInterfaces(allinterfaces);
 107             allinterfaces = Collections.unmodifiableList(allinterfaces);
 108             allInterfacesCache = new SoftReference(allinterfaces);
 109         }
 110         return allinterfaces;
 111     }
 112 
 113     public List subclasses() {
 114         List subclasses = (subclassesCache != null)? (List) subclassesCache.get() : null;
 115         if (subclasses == null) {
 116             List all = vm.allClasses();
 117             subclasses = new ArrayList(0);
 118             Iterator iter = all.iterator();
 119             while (iter.hasNext()) {
 120                 ReferenceType refType = (ReferenceType)iter.next();
 121                 if (refType instanceof ClassType) {
 122                     ClassType clazz = (ClassType)refType;
 123                     ClassType superclass = clazz.superclass();
 124                     if ((superclass != null) && superclass.equals(this)) {
 125                         subclasses.add(refType);
 126                     }
 127                 }
 128             }
 129             subclasses = Collections.unmodifiableList(subclasses);
 130             subclassesCache = new SoftReference(subclasses);
 131         }
 132         return subclasses;
 133     }
 134 
 135     public Method concreteMethodByName(String name, String signature)  {
 136        checkPrepared();
 137        List methods = visibleMethods();
 138        Method method = null;
 139        Iterator iter = methods.iterator();
 140        while (iter.hasNext()) {
 141            Method candidate = (Method)iter.next();
 142            if (candidate.name().equals(name) &&
 143                candidate.signature().equals(signature) &&
 144                !candidate.isAbstract()) {
 145 
 146                method = candidate;
 147                break;
 148            }
 149        }
 150        return method;
 151    }
 152 
 153    List getAllMethods() {
 154         ArrayList list = new ArrayList(methods());
 155         ClassType clazz = superclass();
 156         while (clazz != null) {
 157             list.addAll(clazz.methods());
 158             clazz = clazz.superclass();
 159         }
 160         /*
 161          * Avoid duplicate checking on each method by iterating through
 162          * duplicate-free allInterfaces() rather than recursing
 163          */
 164         Iterator iter = allInterfaces().iterator();
 165         while (iter.hasNext()) {
 166             InterfaceType interfaze = (InterfaceType)iter.next();
 167             list.addAll(interfaze.methods());
 168         }
 169         return list;
 170     }
 171 
 172     List inheritedTypes() {
 173         List inherited = new ArrayList(interfaces());
 174         if (superclass() != null) {
 175             inherited.add(0, superclass()); /* insert at front */
 176         }
 177         return inherited;
 178     }
 179 
 180     public boolean isEnum() {
 181         ClassTypeImpl superclass = (ClassTypeImpl) superclass();
 182         if (superclass != null) {
 183             return superclass.typeNameAsSymbol().equals(vm.javaLangEnum());
 184         } else {
 185             return false;
 186         }
 187     }
 188 
 189     public void setValue(Field field, Value value)
 190         throws InvalidTypeException, ClassNotLoadedException {
 191         vm.throwNotReadOnlyException("ClassType.setValue(...)");
 192     }
 193 
 194 
 195     public Value invokeMethod(ThreadReference threadIntf, Method methodIntf,
 196                               List arguments, int options)
 197                                    throws InvalidTypeException,
 198                                           ClassNotLoadedException,
 199                                           IncompatibleThreadStateException,
 200                                           InvocationException {
 201         vm.throwNotReadOnlyException("ClassType.invokeMethod(...)");
 202         return null;
 203     }
 204 
 205     public ObjectReference newInstance(ThreadReference threadIntf,
 206                                        Method methodIntf,
 207                                        List arguments, int options)
 208                                    throws InvalidTypeException,
 209                                           ClassNotLoadedException,
 210                                           IncompatibleThreadStateException,
 211                                           InvocationException {
 212         vm.throwNotReadOnlyException("ClassType.newInstance(...)");
 213         return null;
 214     }
 215 
 216     @Override
 217     void addVisibleMethods(Map<String, Method> methodMap, Set<InterfaceType> seenInterfaces) {
 218         /*
 219          * Add methods from
 220          * parent types first, so that the methods in this class will
 221          * overwrite them in the hash table
 222          */
 223 
 224         Iterator<InterfaceType> iter = interfaces().iterator();
 225         while (iter.hasNext()) {
 226             InterfaceTypeImpl interfaze = (InterfaceTypeImpl)iter.next();
 227             if (!seenInterfaces.contains(interfaze)) {
 228                 interfaze.addVisibleMethods(methodMap, seenInterfaces);
 229                 seenInterfaces.add(interfaze);
 230             }
 231         }
 232 
 233         ClassTypeImpl clazz = (ClassTypeImpl)superclass();
 234         if (clazz != null) {
 235             clazz.addVisibleMethods(methodMap, seenInterfaces);
 236         }
 237 
 238         addToMethodMap(methodMap, methods());
 239     }
 240 
 241     boolean isAssignableTo(ReferenceType type) {
 242         ClassTypeImpl superclazz = (ClassTypeImpl)superclass();
 243         if (this.equals(type)) {
 244             return true;
 245         } else if ((superclazz != null) && superclazz.isAssignableTo(type)) {
 246             return true;
 247         } else {
 248             List interfaces = interfaces();
 249             Iterator iter = interfaces.iterator();
 250             while (iter.hasNext()) {
 251                 InterfaceTypeImpl interfaze = (InterfaceTypeImpl)iter.next();
 252                 if (interfaze.isAssignableTo(type)) {
 253                     return true;
 254                 }
 255             }
 256             return false;
 257         }
 258     }
 259 
 260     public String toString() {
 261        return "class " + name() + "(" + loaderString() + ")";
 262     }
 263 }