Class ClasspathMonitor

All Implemented Interfaces:
AbstractMonitorMBean, ClasspathMonitorMBean, Shutdownable, Runnable

public class ClasspathMonitor extends AbstractMonitor implements ClasspathMonitorMBean
To avoid classpath problems like double entries of the same class or resource in the classpath there are several methods available.

To get the boot classpath the system property "sun.boot.class.path" is used to get them. This will work of course only for the SunVM.

After an idea from Java Tip 105.

Original this monitor class was part of the PatternTesting project where startup time and performance was increased with v1.5 dramatically. To speed up startup time a FutureTask is used to set up internal structures. For a better performance doublets are now detected with parallel threads. Also some expensive operations are cached now.

Because some stuff are done in parallel we no longer use a WeakHashMap but ConcurrentHashMap to avoid synchronization problems. It is expected that the size of cached objects is small enough and we will not run in any OutOfMemory problems.

Author:
oliver
  • Constructor Details

    • ClasspathMonitor

      protected ClasspathMonitor()
      Instantiates a new classpath monitor.

      Note: The constructor is protected because it is needed by the benchmark subproject which compares different implementations.

  • Method Details

    • getInstance

      public static ClasspathMonitor getInstance()
      Yes, it is a Singleton because it offers only some services. So we don't need the object twice.
      Returns:
      the only instance
    • registerAsMBean

      public static void registerAsMBean()
      With this method you can register the ClasspathMonitor with the default name.

      You can only register the ClasspathMonitor once only. If you want to register it with another name you have to first unregister it.

      See Also:
    • registerAsMBean

      public static void registerAsMBean(String name)
      With this method you can register the ClasspathMonitor with your own name. This is e.g. useful if you have an application server with several applications.

      You can register the ClasspathMonitor once only. If you want to register it with another name you have to first unregister it.

      Parameters:
      name - e.g "my.company.ClasspathMonitor"
      See Also:
    • registerAsMBean

      public static void registerAsMBean(ObjectName name)
      With this method you can register the ClasspathMonitor with your own name. This is e.g. useful if you have an application server with several applications.

      You can only register the ClasspathMonitor once only. If you want to register it with another name you have to first unregister it.

      Parameters:
      name - the name
      Since:
      1.6
      See Also:
    • unregisterAsMBean

      public static void unregisterAsMBean()
      Unregister ClasspathMonitor as MBean.
    • isRegisteredAsMBean

      public static boolean isRegisteredAsMBean()
      If you want to ask JMX if bean is already registered you can ask the MBeanHelper (if you know the object name) or you can ask this method.
      Returns:
      true if MBean is already registered.
      Since:
      1.0
    • whichClass

      public URI whichClass(String name)
      Which class.
      Specified by:
      whichClass in interface ClasspathMonitorMBean
      Parameters:
      name - the classname
      Returns:
      the URI
      See Also:
    • whichClass

      public URI whichClass(Class<?> clazz)
      Where is the given class found in the classpath? Which class was loaded from which URI?.
      Parameters:
      clazz - the class
      Returns:
      file or jar path
    • whichClassPath

      public URI whichClassPath(String classname)
      Returns the jar file or path where the given classname was found.
      Parameters:
      classname - e.g. java.lang.String
      Returns:
      jar or path as URI
    • whichClassPath

      public URI whichClassPath(Class<?> clazz)
      Returns the jar file or path where the given class was found.
      Parameters:
      clazz - e.g. Sting.class
      Returns:
      jar or path as URI
    • whichClassPath

      public URI whichClassPath(Package p)
      Which class path.
      Parameters:
      p - the p
      Returns:
      the uRI
    • whichResourcePath

      public URI whichResourcePath(String resource)
      Returns the jar file or path where the given resource was found.
      Parameters:
      resource - e.g. log4j.properties
      Returns:
      jar or path as URI
    • whichClassJar

      public JarFile whichClassJar(Class<?> clazz)
      Which class jar.
      Parameters:
      clazz - the clazz
      Returns:
      the jar file
    • whichClassJar

      public JarFile whichClassJar(String classname)
      Which class jar.
      Parameters:
      classname - the classname
      Returns:
      the jar file
    • whichPath

      public Path whichPath(Class<?> clazz)
      Returns the path of the given clazz.
      Parameters:
      clazz - the class
      Returns:
      class path
      Since:
      1.1
    • whichPath

      public Path whichPath(String resource)
      Returns the path of the given resource image. This method was introduced for the module system as described in JEP 220 (Modular Run-Time Images).
      Parameters:
      resource - the resource
      Returns:
      resource path
      Since:
      1.1
    • whichResourceJar

      public JarFile whichResourceJar(String resource)
      Which resource jar.
      Parameters:
      resource - the resource
      Returns:
      the jar file
    • whichResourceJar

      public static JarFile whichResourceJar(URI resource)
      Which resource jar.
      Parameters:
      resource - the resource
      Returns:
      the jar file
    • getResources

      public Enumeration<URI> getResources(String name)
      Gets the resources.
      Parameters:
      name - the resource name
      Returns:
      the resources
    • getResource

      public static URL getResource(String name)
      Gets the resource.
      Parameters:
      name - the resource name
      Returns:
      the resource
    • getNoClasses

      public int getNoClasses(Class<?> cl)
      Gets the no classes.
      Parameters:
      cl - the class
      Returns:
      number of classes
    • getNoClasses

      public int getNoClasses(String classname)
      Gets the no classes.
      Specified by:
      getNoClasses in interface ClasspathMonitorMBean
      Parameters:
      classname - the classname
      Returns:
      number of classes
      See Also:
    • isDoublet

      public boolean isDoublet(Class<?> clazz)
      Is the given class a doublet, i.e. can it be found more than once in the classpath?

      Note: Because this method is needed by other methods like getIncompatibleClassList() the result of it is cached since 1.5. This speeds up this method about the factor 2000 and more:

       Implementation | Mode  | Score    | Unit
       ---------------+-------+----------+-------
       old (till 1.4) | thrpt |    35514 | ops/s
       new (cached)   | thrpt | 92968300 | ops/s
       

      This results were calculated with the help of JMH and was executed on a Dell Latitude e6520 with i5 processor (i5-2540M CPU @ 2.60GHz).

      Since 1.6.2 this functionality is now located in the extracted DoubletDigger class.

      Specified by:
      isDoublet in interface ClasspathMonitorMBean
      Parameters:
      clazz - the class to be checked
      Returns:
      true if class is found more than once in the classpath
      See Also:
    • getFirstDoublet

      public URI getFirstDoublet(Class<?> clazz)
      Gets the first doublet.
      Specified by:
      getFirstDoublet in interface ClasspathMonitorMBean
      Parameters:
      clazz - the class
      Returns:
      the first doublet
      See Also:
    • getDoublet

      public URI getDoublet(Class<?> clazz, int nr)
      Gets the doublet.
      Specified by:
      getDoublet in interface ClasspathMonitorMBean
      Parameters:
      clazz - the clazz
      nr - the nr of the doublet (starting at 0)
      Returns:
      the doublet
    • getDoubletList

      public List<Class<?>> getDoubletList()
      Gets the doublet list.
      Returns:
      the doublet list
    • getDoublets

      public String[] getDoublets()
      Gets the doublets.
      Specified by:
      getDoublets in interface ClasspathMonitorMBean
      Returns:
      the doublets
      See Also:
    • getDoubletClasspath

      public String[] getDoubletClasspath()
      Gets the doublet classpath.
      Specified by:
      getDoubletClasspath in interface ClasspathMonitorMBean
      Returns:
      the doublet classpath
    • getDoubletClasspathURIs

      public URI[] getDoubletClasspathURIs()
      Gets the doublet classpath as array of URIs
      Returns:
      an array with the doublets
    • getClassLoaderDetails

      public String getClassLoaderDetails()
      Dumps the internal fields of the classloader (after an idea from "Java ist auch eine Insel").
      Returns:
      the class loader details
    • isClassloaderSupported

      public boolean isClassloaderSupported()
      Checks if is classloader supported.
      Returns:
      true if it is a known classloader
    • getClassloaderInfo

      public String getClassloaderInfo()
      Returns some information about the classloader. At least the user should be informed if it is a unknown classloader which is not supported or not tested.
      Specified by:
      getClassloaderInfo in interface ClasspathMonitorMBean
      Returns:
      e.g. "unknown classloader xxx - classpath can be wrong"
    • getLoadedPackages

      public String[] getLoadedPackages()
      Gets the loaded packages.
      Specified by:
      getLoadedPackages in interface ClasspathMonitorMBean
      Returns:
      the loaded packages
      See Also:
    • getLoadedPackageArray

      public Package[] getLoadedPackageArray()
      This method is used by PatternTesting Samples (in packages.jsp). So it is left here as wrapper around ClasspathDigger.
      Returns:
      array of packages
    • getLoadedPackagesAsString

      public String getLoadedPackagesAsString()
      If you want to dump all packages you can use this method. The output will be sorted.
      Returns:
      each package in a single line
    • getLoadedClassList

      public List<Class<?>> getLoadedClassList()
      Returns a list of classes which were loaded by the classloader.
      Returns:
      list of classes
    • getLoadedClasses

      public String[] getLoadedClasses()
      As MBean a string array could be displayed by the 'jconsole'. A class array not.
      Specified by:
      getLoadedClasses in interface ClasspathMonitorMBean
      Returns:
      the classes as sorted string array
    • getLoadedClassesAsString

      public String getLoadedClassesAsString()
      Gets the loaded classes as string.
      Returns:
      the loaded classes as string
    • isLoaded

      public boolean isLoaded(String classname)
      Checks if the given classname is loaded. Why does we use not Class as parameter here? If you would allow a parameter of type "Class" this class will be problably loaded before and this method will return always true!
      Specified by:
      isLoaded in interface ClasspathMonitorMBean
      Parameters:
      classname - name of the class
      Returns:
      true if class is loaded
    • getUnusedClasses

      public String[] getUnusedClasses()
      Unused classes are classes which are not loaded but which are found in the classpath.
      Specified by:
      getUnusedClasses in interface ClasspathMonitorMBean
      Returns:
      unused classes
      See Also:
    • getClasspathClasses

      public String[] getClasspathClasses()
      Scans the classpath for all classes. For performance reason we return no longer a copy but the origin array. Don't do changes for the returned array!
      Specified by:
      getClasspathClasses in interface ClasspathMonitorMBean
      Returns:
      all classes as String array
    • getClasspathClassList

      public Collection<String> getClasspathClassList(String packageName)
      Gets the classes of a given package name as collection.
      Parameters:
      packageName - the package name
      Returns:
      the classpath class list
    • getClassList

      public <T> Collection<Class<? extends T>> getClassList(String packageName, Class<T> type)
      Gets the classes of the given type.
      Type Parameters:
      T - the generic type
      Parameters:
      packageName - the package name
      type - the type
      Returns:
      the classes
    • getConcreteClassList

      @Deprecated(since="2.3", forRemoval=true) public Collection<Class<?>> getConcreteClassList(String packageName)
      Deprecated, for removal: This API element is subject to removal in a future version.
      dead classes may be loaded
      Gets a list of concrete classes. These are classes which can be instantiated, i.e. they are not abstract and have a default constructor.

      TODO: Will be removed in 2.5

      Parameters:
      packageName - the package name
      Returns:
      the concrete class list
    • getUsedClasspathSet

      public SortedSet<URI> getUsedClasspathSet()
      Gets the loaded classpath (without the bootclasspath) as sorted set. Since v1.5 this method is about 5 times faster than the old implementation by caching the result from previous calls.

      Here the result from running some benchmarks with the old and new implementation: Profiling with JMH gives the following result:

       Implementation | Mode  | Score             | Error (99.9%) | Unit
       ---------------+-------+-------------------+---------------+-------
       new (v1.5)     | thrpt | 6.495745459743192 | 0.14376149437 | ops/ms
       old (v1.4)     | thrpt | 1.167003226917474 | 0.01126705718 | ops/ms
       new (v1.5)     | avgt  | 0.149637883043804 | 0.00084667052 | ms/op
       old (v1.4)     | avgt  | 0.860845377760151 | 0.02615918865 | ms/op
       

      As framework for the benchmarks JMH was used.

      Returns:
      the loaded classpath (excluding the bootclasspath)
    • getUsedClasspath

      public String[] getUsedClasspath()
      It might be that the used classpath changes during the calculation of it. So it is only a good approximation how it looks at the moment of the call.
      Specified by:
      getUsedClasspath in interface ClasspathMonitorMBean
      Returns:
      the used classpath
    • getUsedClasspathURIs

      public URI[] getUsedClasspathURIs()
      It might be that the used classpath changes during the calculation of it. So it is only a good approximation how it looks at the moment of the call.
      Returns:
      the used classpath as array of URIs
    • getUnusedClasspath

      public String[] getUnusedClasspath()
      The unused classpath is the path which is not used by the classloader.
      Specified by:
      getUnusedClasspath in interface ClasspathMonitorMBean
      Returns:
      the unused classpath (sorted)
    • getUnusedClasspathSet

      public SortedSet<URI> getUnusedClasspathSet()
      The unused classpath is the path which are not used by the classloader.
      Returns:
      the unused classpath (sorted)
    • getBootClasspath

      public String[] getBootClasspath()
      To get the boot classpath the sytem property "sun.boot.class.path" is used to get them. This will work of course only for the SunVM and only till Java 8.
      Specified by:
      getBootClasspath in interface ClasspathMonitorMBean
      Returns:
      the boot classpath as String array
    • getClasspath

      public String[] getClasspath()
      The classpath is stored in the system property "java.class.path". And this is the classpath which will be returned.
      Specified by:
      getClasspath in interface ClasspathMonitorMBean
      Returns:
      the classpath as String array
    • getClasspathSet

      public SortedSet<URI> getClasspathSet()
      The classpath is stored in the system property "java.class.path" as sorted set.
      Returns:
      the classpath set
      Since:
      2.0
    • getSerialVersionUID

      public Long getSerialVersionUID(String classname) throws IllegalAccessException
      Gets the serial version uid.
      Specified by:
      getSerialVersionUID in interface ClasspathMonitorMBean
      Parameters:
      classname - name of the class
      Returns:
      the serialVersionUID
      Throws:
      IllegalAccessException - if class can't be accessed
    • getSerialVersionUID

      public Long getSerialVersionUID(Class<?> clazz) throws IllegalAccessException
      Gets the serial version uid.
      Parameters:
      clazz - the clazz
      Returns:
      the serial version uid
      Throws:
      IllegalAccessException - the illegal access exception
    • getManifestEntries

      public String[] getManifestEntries(Class<?> clazz)
      If a MANIFEST is found for a given class the attributes in this file should be returned as a string array. E.g. for commons-lang-2.3.jar the string array may looks like
       Manifest-Version: 1.0
       Ant-Version: Apache Ant 1.6.5
       Created-By: 1.3.1_09-85 ("Apple Computer, Inc.")
       Package: org.apache.commons.lang
       Extension-Name: commons-lang
       Specification-Version: 2.3
       Specification-Vendor: Apache Software Foundation
       Specification-Title: Commons Lang
       Implementation-Version: 2.3
       Implementation-Vendor: Apache Software Foundation
       Implementation-Title: Commons Lang
       Implementation-Vendor-Id: org.apache
       X-Compile-Source-JDK: 1.3
       X-Compile-Target-JDK: 1.1
       
      Parameters:
      clazz - the clazz
      Returns:
      the attribute entries of the Manifest (or emtpy array if no Manifest or no attributes are found)
    • getManifestEntries

      public String[] getManifestEntries(String classname)
      If a MANIFEST is found for a given class the attributes in this file should be returned as a string array. E.g. for commons-lang-2.3.jar the string array may look like
       Manifest-Version: 1.0
       Ant-Version: Apache Ant 1.6.5
       Created-By: 1.3.1_09-85 ("Apple Computer, Inc.")
       Package: org.apache.commons.lang
       Extension-Name: commons-lang
       Specification-Version: 2.3
       Specification-Vendor: Apache Software Foundation
       Specification-Title: Commons Lang
       Implementation-Version: 2.3
       Implementation-Vendor: Apache Software Foundation
       Implementation-Title: Commons Lang
       Implementation-Vendor-Id: org.apache
       X-Compile-Source-JDK: 1.3
       X-Compile-Target-JDK: 1.1
       
      Specified by:
      getManifestEntries in interface ClasspathMonitorMBean
      Parameters:
      classname - (must be in the classpath, otherwise you'll get a IllegalArgumentException)
      Returns:
      the attribute entries of the Manifest (or emtpy array if no Manifest or no attributes are found)
    • getIncompatibleClassList

      public List<Class<?>> getIncompatibleClassList()
      Looks for each doublet if it has a different doublets. For the performance reason it looks in the incompatibleClassList from the last time if it is already found. This is done because normally the number of incompatible classes does not decrease.
      Returns:
      a sorted list of incompatible classes
    • getIncompatibleClasses

      public String[] getIncompatibleClasses()
      Incompatible classes are doublets with different byte codes.
      Specified by:
      getIncompatibleClasses in interface ClasspathMonitorMBean
      Returns:
      doublet classes with different byte codes.
    • getIncompatibleClasspath

      public String[] getIncompatibleClasspath()
      Gets the incompatible classpath.
      Specified by:
      getIncompatibleClasspath in interface ClasspathMonitorMBean
      Returns:
      the classpathes where incompatible classes were found
    • getIncompatibleClasspathURIs

      public URI[] getIncompatibleClasspathURIs()
      Gets the incompatible classpath as array of URIs.
      Returns:
      the classpathes where incompatible classes were found
    • addAsShutdownHook

      public static void addAsShutdownHook()
      You can register the instance as shutdown hook. If the VM is terminated the attributes are logged and dumped to a text file in the tmp directory.
      See Also:
    • removeAsShutdownHook

      public static void removeAsShutdownHook()
      If you have registered the instance you can now de-register it.
      Since:
      1.0
      See Also:
    • logMe

      public void logMe()
      Logs the different array to the log output.
      Specified by:
      logMe in interface AbstractMonitorMBean
      Specified by:
      logMe in class AbstractMonitor
    • dumpMe

      public void dumpMe(File dumpDir) throws IOException
      This operation dumps the different MBean attributes to the given directory.

      Note: Till 1.5 the different attributes are dumped to a single file. Now each attribute is dumped into its own file. The given file parameter is the directory for these files.

      To dump the different attributes (which are mainly given as array) we use the internal 'dumpArray()' method. This method uses reflection to call the corresponding getter method for that attribute. The reason for this approach is that we can better control exceptions if they happens in one of the getter method. If it happens it is ignored (but logged) and the next attribute is dumped.

      Overrides:
      dumpMe in class AbstractMonitor
      Parameters:
      dumpDir - the directory where the attributes are dumped to.
      Throws:
      IOException - Signals that an I/O exception has occurred.
      Since:
      1.5
    • toString

      public String toString()
      We don't want to use the toString() implementation of the Thread class so we use our own one.
      Overrides:
      toString in class AbstractMonitor
      Returns:
      the string
      See Also:
    • isMultiThreadingEnabled

      public boolean isMultiThreadingEnabled()
      Is multi threading enabled? Multi threading is automatically enabled if more than one processor is found. Otherwise you can use set via the system property "multiThreadingEnabled=true" to activate it.
      Returns:
      true if multi threading is enabled for this class.
      Since:
      0.9.7
      See Also:
    • setMultiThreadingEnabled

      public void setMultiThreadingEnabled(boolean enabled)
      Here you can enable or disable the (experimental) multi threading mode to see if it is really faster on a mult-core machine.
      Parameters:
      enabled - true if multithreading is enabled
      Since:
      0.9.7
      See Also: