/*
* This file is part of Mockey, a tool for testing application
* interactions over HTTP, with a focus on testing web services,
* specifically web applications that consume XML, JSON, and HTML.
*
* Copyright (C) 2012 Authors:
*
* chad.lafontaine (chad.lafontaine AT gmail DOT com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
package com.mockey.plugin;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.log4j.Logger;
/**
* This class is used to search for all classes that exist in a package (i.e.
* name-space) with a package-info.class as a peer for the purpose of
* package-level annotations filtering. In other words, we want to find only
* classes that exist in a package with package-level annotations.
*
* @author chadlafontaine
*
*/
class PackageInfoPeerClassFinder {
private static Logger logger = Logger.getLogger(PackageInfoPeerClassFinder.class);
/**
* Given a path to the Mockey.jar file, and when package-info classes are
* found, then all peer classes are gathered into a list.
*
* @param pathToJarContainingClasses
* a list of all classes who share a package with a
* package-info.class class.
* @return
* @throws Exception
*/
public static List<PackageInfo> findPackageInfo() throws Exception {
List<PackageInfo> packageInfoSet = new ArrayList<PackageInfo>();
List<String> visitedClasses = new ArrayList<String>();
File jarFile = new File("Mockey.jar");
if (jarFile.exists()) {
// STEP 1: go through all classes.
URL jar = jarFile.toURI().toURL();
ZipInputStream zip = new ZipInputStream(jar.openStream());
ZipEntry entry;
while ((entry = zip.getNextEntry()) != null) {
if (entry.getName().endsWith("package-info.class")) {
PackageInfo packageInfo = new PackageInfo(getPackageNameFromPackageInfoClass(entry.getName()));
packageInfoSet.add(packageInfo);
} else if (entry.getName().endsWith(".class")) {
visitedClasses.add(getCleanClassName(entry.getName()));
}
}
// STEP 2: add all classes with matching name-space/package name to
// the right Package Info
for (PackageInfo pi : packageInfoSet) {
for (String className : visitedClasses) {
if (className.startsWith(pi.getName())) {
pi.addClassNameToPackage(className);
}
}
}
} else {
String[] packageListToLoad = new String[] { "com.mockey.plugin", };
for (String pName : packageListToLoad) {
Package p = Package.getPackage(pName);
if (p != null) {
PackageInfo pi = new PackageInfo(p.getName());
pi.addClassNameToPackage(SampleRequestInspector.class.getName());
packageInfoSet.add(pi);
} else {
logger.debug("Wow, due to lazy class loading we don't see "
+ SampleRequestInspector.class.getName());
}
}
}
return packageInfoSet;
}
/**
*
* @param packageInfoClassName
* - must include the string value 'package-info'.
* @return package name in the format xx.yyy.cccc.etc if available, null
* otherwise.
*/
public static String getPackageNameFromPackageInfoClass(String packageInfoClassName) {
String pckge = null;
if (packageInfoClassName != null) {
int index = packageInfoClassName.indexOf("package-info");
if (index > -1) {
pckge = packageInfoClassName.substring(0, index - 1);
return getCleanClassName(pckge);
}
}
return pckge;
}
/**
* Takes a string value and ensures it is has good form. For example:
*
* <pre>
* 'com/xxx/yyy/ClassName.class' becomes 'com.xxx.yyy.ClassName'
* 'com/xxx/yyy/ClassName' becomes 'com.xxx.yyy.ClassName'
* 'com.xxx.yyy.ClassName.class' becomes 'com.xxx.yyy.ClassName'
* </pre>
*
* @param className
* @return
*/
public static String getCleanClassName(String className) {
if (className != null) {
return className.replaceAll("[$].*", "").replaceAll("[.]class", "").replace('/', '.');
} else {
return null;
}
}
}