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 usesCacheKeyImpl
(ICacheKey
) CacheKeyImpl
uses 3 classes external to theorg.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 onCacheKeyImpl
org.jasig.portal.rendering.sax.SaxCacheFilterImplpublic final ICacheKey dummyKey=new CacheKeyImpl("");
org.jasig.portal.layout.uportal2.UserAwareLayoutManager
: implements theICacheable
interfaceorg.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
andorg.jasig.portal.rendering.attributes.url.ContextPathAwareAttributeDecoratorAndProcessor
both call the static methodServletPathContextResolver.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.