1 Reply Latest reply on Nov 20, 2007 8:16 AM by Adrian Brock

    Class metadata scope doesn't understand classloaders

    Adrian Brock Master

      There's a problem with the metadata repository and the class scope.
      The issue is that it uses a String to identify the class
      so two different classloaders with the same class will clash.

      I'm changing the scope qualifier to be an Object such that
      the class scope can do:
      scopeKey.addScope(new Scope(CommonLevels.CLASS, theClass);
      which will form a unique key across classloaders.

      As part of the work I'm introducing a new MetaDataRetrievalFactory
      which can be installed on the repository.

      I'm adding a class factory by default to the Base implementation
      so we no longer have to maintain the class scopes in the repository,
      just reference them from scope key as above.
      e.g. the deployer scope test no longer has to maintain the class
      scope in the deploy/undeploy.

      This creates a problem for the MC, where it doesn't know the classloader
      until PreInstall. I don't really know how to fix this cleanly, instead
      I've hacked the KernelScopeInfo to replace the string version of the scope
      (the string is known from the xml) to the class loaded from the bean's classloader.

      
       @Override
       public ScopeKey getScope()
       {
       // THIS IS A HACK - the scope originally gets initialise with a class name, we fix it to have the class
       ScopeKey key = super.getScope();
       Scope scope = key.getScope(CommonLevels.CLASS);
       if (scope == null)
       return key;
       Object qualifier = scope.getQualifier();
       if (qualifier instanceof Class)
       return key;
      
       String className = (String) qualifier;
       ClassLoader cl = null;
       try
       {
       cl = Configurator.getClassLoader(beanMetaData);
       }
       catch (Throwable t)
       {
       throw new RuntimeException("Error getting classloader for " + key, t);
       }
       Class<?> clazz = null;
       try
       {
       clazz = cl.loadClass(className);
       }
       catch (ClassNotFoundException e)
       {
       throw new RuntimeException("Unable to load class: " + className + " for " + key, e);
       }
       key.addScope(new Scope(CommonLevels.CLASS, clazz));
       return key;
       }
      


      Further I added some convience methods for the component metadata
      (ComponentMutableMetaData) so you can do things like
      memoryMetaDataLoader.addAnnotation(method(info), myAnnotation);
      While I was there I tidied up some of the Signature uses.
      There are now easy mechanism to create one from a MethodInfo, etc.

      The last also avoids some unnecessary multiple converion of parameter types
      that was happening.