Code Analysis

Code Analysis

I'm using a code analysis tool called Classycle (eclipse plugin here) to find dependencies and analyze the relationships between the classes and packages of UP3. Hopefully this exercise will help us refactor/restructure the codebase, and ultimatly lead to a cleaner transition to Maven 2.

Example

On the right you can see a screenshot from my Eclipse workspace. The class org.jasig.portal.caching.CacheKeyImpl is highlighted. Classcyle tells us that:

  • CacheKeyImpl is used by 25 other classes,
  • 1 class within the org.jasig.portal.caching package uses CacheKeyImpl (ICacheKey)
  • CacheKeyImpl uses 3 classes external to the org.jasig.portal.caching package

We know that CacheKeyImpl is a concrete class, and it implements the ICacheKey interface. With this in mind, let's take a deeper look at some of the 25 classes that reference CacheKeyImpl.

  • org.jasig.portal.rendering.sax.SaxCacheFilterImpl: has a direct dependency on CacheKeyImpl
    org.jasig.portal.rendering.sax.SaxCacheFilterImpl
    public final ICacheKey dummyKey=new CacheKeyImpl("");
    
  • org.jasig.portal.layout.uportal2.UserAwareLayoutManager: implements the ICacheable interface
    org.jasig.portal.layout.uportal2.UserAwareLayoutManager
        /* (non-Javadoc)
         * @see org.jasig.portal.caching.ICacheable#generateKey()
         */
        public ICacheKey generateKey() {
            if(currentLayoutManager==null) {
                return null;
            }
            
            try {
                return new CacheKeyImpl(currentLayoutManager.getCacheKey());
            } catch (PortalException e) {
                logger.error("generateKey() - exception raised while trying to obtain user layout manager cache key", e);
                return null;
            }
        }
    

These are just two examples (there are more) which suggest that clients or implementers of the UP3 caching sub-system would benefit from an ICacheKeyFactory, or some other method (IoC) of obtaining an ICacheKey.

Without any refactoring

  • the SaxCacheFilterImpl M2 artifact would have dependencies on both the framework-cache-api and framework-cache-impl artifact
  • the UserAwareLayoutManager would have dependencies on both the cache api and cache impl as well.

By refactoring we produce loosely coupled code working together via well-defined interfaces, and the framework-render-saximpl and framwork-layout-up2impl only depend on framework-cache-api.

Another Example

org.jasig.portal.context.ServletPathContextResolver implements org.jasig.portal.context.IContextResolver. There are two classes that have direct dependencies on ServletPathContextResolver:

  • org.jasig.portal.url.ContextPathDecorator and org.jasig.portal.rendering.attributes.url.ContextPathAwareAttributeDecoratorAndProcessor both call the static method ServletPathContextResolver.getContextPathElement(HttpServletRequest).
    ServletPathContextResolver.getContextPathElement(HttpServletRequest)
        /**
         * Returns context path element for the current request. For instance, if the current context
         * is uP3, the method will return "uP3" unless uP3 context was selected because it is the default
         * context and either no context was specified in the request, or a wrong context was specified.
         * @param req
         * @return
         */
        public static String getContextPathElement(HttpServletRequest req) {
            return (String) req.getAttribute(PORTAL_CONTEXT_ATTRIBUTE_NAME);
        }
    

As it stands now, the framework-url-impl and framework-rendering-impl both have a dependency on framework-context-api and framework-context-impl. If this static method could be refactored into the IContextResolver interface or into a seperate utility class, then the implementations only need to depend on the framework-context-api artifact, and we have promoted loose coupling by well-defined interfaces, decreased the complexity of the dependency graph, and will make it easier to move to Maven 2.