/* * $Id$ * * Copyright 2006, The jCoderZ.org Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * Neither the name of the jCoderZ.org Project nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jcoderz.phoenix.report; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.jcoderz.commons.util.Assert; import org.jcoderz.commons.util.HashCode; import org.jcoderz.commons.util.IoUtil; import org.jcoderz.commons.util.ObjectUtil; /** * This class holds resource information about a Java class. * * @author Michael Griffel */ public final class ResourceInfo { /** holds a map from resource name to ResourceInfo */ private static final Map<String, ResourceInfo> RESOURCES = Collections.synchronizedMap(new HashMap<String, ResourceInfo>()); /** holds a map from package / classname to ResourceInfo */ private static final Map<String, ResourceInfo> RESOURCES_BY_CLASS = Collections.synchronizedMap(new HashMap<String, ResourceInfo>()); private static final String CLASSNAME = ResourceInfo.class.getName(); private static final Logger logger = Logger.getLogger(CLASSNAME); private final String mResourceName; private final String mPackage; private final String mSourcDir; private final String mClassname; /** Lazy initialized number of source lines value. */ private int mLinesOfCode = -1; /** Lazy initialized hash code value. */ private int mHashCode = -1; private ResourceInfo (String name, String pkg, String sourceDir) { if (logger.isLoggable(Level.FINER)) { logger.entering(CLASSNAME, "<init>", new Object[]{name, pkg, sourceDir}); } Assert.notNull(name, "name"); Assert.notNull(sourceDir, "sourceDir"); mResourceName = checkName(name).intern(); mPackage = ObjectUtil.toStringOrEmpty(pkg); mSourcDir = checkName(sourceDir).intern(); mClassname = determineClassName(name).intern(); if (logger.isLoggable(Level.FINER)) { logger.exiting(CLASSNAME, "<init>", this); } } /** * Registers the a new resource with the given parameters. * @param name the name of the resource. * @param pkg the Java package of the resource. * @param sourceDir the source directory of the resource. * @return the registered resource info. */ public static ResourceInfo register (String name, String pkg, String sourceDir) { final String resourceName = checkName(name); final ResourceInfo result; if (!RESOURCES.containsKey(resourceName)) { result = new ResourceInfo(resourceName, pkg, sourceDir); add(resourceName, result); } else { result = RESOURCES.get(resourceName); final ResourceInfo newInfo = new ResourceInfo(resourceName, pkg, sourceDir); // sanity check Assert.assertEquals("Ups, the ResourceInfo w/ the name " + resourceName + " is already registered with different parameters!", result, newInfo); } return result; } /** * Locates the resource with the given name. * * @param name resource name. * @return the resource for the given name or <tt>null</tt> if not found. */ public static ResourceInfo lookup (String name) { String lookupName = name; ResourceInfo result = RESOURCES.get(lookupName); if (result == null) { lookupName = checkName(name); result = RESOURCES.get(lookupName); } if (result == null) { logger.finer("### ResourceInfo not found for '" + lookupName + "'"); } return result; } /** * Searches the resource with the given class name and package. * * @param packageName resource package name. * @param className resource class name. * @return the resource for the given name or <tt>null</tt> if not found. */ public static ResourceInfo lookup (String packageName, String className) { final String key = combineName(packageName, className); final ResourceInfo result = RESOURCES_BY_CLASS.get(key); if (result == null) { logger.finer("### ResourceInfo not found for '" + key + "'"); } return result; } static String dump () { return RESOURCES.toString(); } /** * Returns the number of lines for the given file <tt>filename</tt>. * @param fileName the name of the file. * @return the number of lines. * @throws IOException in case of an I/O problem. * @throws FileNotFoundException in case the named file does * not exists or is a directory. */ public static int countLinesOfCode (String fileName) throws IOException, FileNotFoundException { int counter = 0; final BufferedReader reader = new BufferedReader(new FileReader(fileName)); try { while (reader.readLine() != null) { ++counter; } } finally { IoUtil.close(reader); } return counter; } /** {@inheritDoc} */ public boolean equals (Object obj) { boolean result = false; if (this == obj) { result = true; } else if (obj instanceof ResourceInfo) { final ResourceInfo o = (ResourceInfo) obj; result = ObjectUtil.equals(mResourceName, o.getResourceName()) && ObjectUtil.equals(mPackage, o.getPackage()) && ObjectUtil.equals(mSourcDir, o.getSourcDir()); } else { result = false; } return result; } /** {@inheritDoc} */ public int hashCode () { if (mHashCode == -1) { final HashCode hashCode = new HashCode(); hashCode.hash(mResourceName); hashCode.hash(mPackage); hashCode.hash(mSourcDir); mHashCode = hashCode.hashCode(); } return mHashCode; } /** * Returns the linesOfCode. * * @return the linesOfCode. */ public int getLinesOfCode () { if (mLinesOfCode == -1) { try { mLinesOfCode = countLinesOfCode(mResourceName); } catch (IOException e) { mLinesOfCode = 0; logger.log(Level.FINER, "Cannot read the resource with the name " + mResourceName, e); } } return mLinesOfCode; } /** * Returns the package. * * @return the package. */ public String getPackage () { return mPackage; } /** * Returns the resourceName. * * @return the resourceName. */ public String getResourceName () { return mResourceName; } /** * Returns the sourcDir. * * @return the sourcDir. */ public String getSourcDir () { return mSourcDir; } /** {@inheritDoc} */ public String toString () { return "[ResourceInfo: name=" + mResourceName + ", pkg=" + mPackage + ", sourceDir=" + mSourcDir + ", mClassname=" + mClassname + "]"; } /** * Returns the class name. * @return the class name. */ public String getClassname () { return mClassname; } private String determineClassName (String name) { String result = ""; final String magic = ".java"; if (name.endsWith(magic)) { final int lastSlashPos = name.lastIndexOf(File.separator); if (lastSlashPos != -1) { result = name.substring(lastSlashPos + File.separator.length()); result = result.substring(0, result.indexOf(magic)); } } return result; } private static void add (String name, ResourceInfo info) { synchronized (RESOURCES) { RESOURCES.put(name, info); RESOURCES_BY_CLASS.put( combineName(info.getPackage(), info.getClassname()), info); } } private static String combineName (String packageName, String className) { return ObjectUtil.toStringOrEmpty(packageName) + "--" + ObjectUtil.toStringOrEmpty(className); } private static String checkName (String lookupName) { String name = ObjectUtil.toStringOrEmpty(lookupName); if (!RESOURCES.containsKey(name)) { try { name = new File(name).getCanonicalPath(); } catch (IOException ex) { throw new RuntimeException( "Uuppss, this was not expected in 'getCanonicalPath' " + " for '" + name + "'.", ex); } } return name; } }