You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by da...@apache.org on 2005/06/08 00:32:52 UTC
svn commit: r189461 [2/3] - in /cocoon/whiteboard/osgi: ./ ant/
ant/html_template/ ant/src/ ant/src/org/ ant/src/org/knopflerfish/
ant/src/org/knopflerfish/ant/ ant/src/org/knopflerfish/ant/taskdefs/
ant/src/org/knopflerfish/ant/taskdefs/bundle/ bundles/ bundles/cocoon/
bundles/cocoon/src/ bundles/cocoon_testcase/ bundles/cocoon_testcase/src/
bundles/cocoon_testcase/src/org/ bundles/cocoon_testcase/src/org/apache/
bundles/cocoon_testcase/src/org/apache/cocoon/
bundles/cocoon_testcase/src/org/apache/cocoon/service/
bundles/cocoon_testcase/src/org/apache/cocoon/service/cocoon_testcase/
bundles/cocoon_testcase/src/org/apache/cocoon/service/cocoon_testcase/impl/
bundles/test/ bundles/test/src/ bundles/test/src/org/
bundles/test/src/org/apache/ bundles/test/src/org/apache/cocoon/
bundles/test/src/org/apache/cocoon/service/
bundles/test/src/org/apache/cocoon/service/test/
bundles/test/src/org/apache/cocoon/service/test/impl/ jars-external/
jars-external/junit/ jars/ legal/
Added: cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleHTMLExtractorTask.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleHTMLExtractorTask.java?rev=189461&view=auto
==============================================================================
--- cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleHTMLExtractorTask.java (added)
+++ cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleHTMLExtractorTask.java Tue Jun 7 15:32:48 2005
@@ -0,0 +1,1061 @@
+/*
+ * Copyright (c) 2003, KNOPFLERFISH 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 KNOPFLERFISH 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER OR 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.knopflerfish.ant.taskdefs.bundle;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.classfile.*;
+import org.apache.bcel.generic.Type;
+import org.apache.bcel.generic.BasicType;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+import java.util.zip.*;
+
+/**
+ * <p>
+ * Task that analyzes a set of bundle jar files and builds HTML documentation
+ * from these bundles. Also creates cross-references to bundle dependecies.
+ * </p>
+ *
+ * <p>
+ * All generated HTML will be stored in the same directory stucture as
+ * the scanned jars, e.g a jar file
+ * <pre>
+ * jars/log/log-api.jar
+ * </pre>
+ * will have a corresponding
+ * <pre>
+ * jars/log/log-api.html
+ * </pre>
+ *
+ * <p>
+ * Bundle jar files files are analyzed using the static manifest attributes.
+ * </p>
+ *
+ * <h3>Parameters</h3>
+ *
+ * <table border=>
+ * <tr>
+ * <td valign=top><b>Attribute</b></td>
+ * <td valign=top><b>Description</b></td>
+ * <td valign=top><b>Required</b></td>
+ * </tr>
+ * <tr>
+ * <td valign=top>javadocRelPath</td>
+ * <td valign=top>Relative path (from baseDir) to javadocs.
+ * </td>
+ * <td valign=top>No.<br> Default value is "."</td>
+ * </tr>
+ * <tr>
+ * <td valign=top>baseDir</td>
+ * <td valign=top>
+ * Base directory for scanning for jar files.
+ * </td>
+ * <td valign=top>No.<br> Default value is "."</td>
+ * </tr>
+ * <td valign=top>templateHTMLDir</td>
+ * <td valign=top>
+ * Directory containing HTML template files. This directory must
+ * contain the files:
+ * <pre>
+ * bundle_index.html
+ * bundle_list.html
+ * bundle_main.html
+ * style.css
+ * </pre>
+ * </td>
+ * </td>
+ * <td valign=top>No.<br> Default value is "."</td>
+ * </tr>
+ *
+ * <tr>
+ * <td valign=top>systemPackageSet</td>
+ * <td valign=top>
+ * Comma-spearated set of packages which are system packages and
+ * thus globally available.
+ * These are not cross-referenced.
+ * </td>
+ * <td valign=top>No.<br>
+ * Default value is "javax.swing,javax.accessibility,javax.servlet,javax.xml,org.xml,org.w3c,java,com.sun"
+ </td>
+ *
+ * <tr>
+ * <td valign=top>skipAttribSet</td>
+ * <td valign=top>
+ * Comma-spearated set of manifest attributes which shouldn't be printed.
+ * </td>
+ * <td valign=top>No.<br>
+ * Default value is "Manifest-Version,Ant-Version,Bundle-Config,Created-By,Built-From"
+ </td>
+ *
+ * </table>
+ *
+ * <h3>Parameters specified as nested elements</h3>
+ * <h4>fileset</h4>
+ *
+ * (required)<br>
+ * <p>
+ * All jar files must be specified as a fileset. No jar files
+ * are ignored.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ *
+ * <pre>
+ * <bundlehtml templateHTMLDir = "${ant.dir}/html_template"
+ * baseDir = "${release.dir}/jars"
+ * javadocRelPath = "../javadoc"
+ * >
+ *
+ * <fileset dir="${release.dir}/jars">
+ * <include name = "**/*.jar"/>
+ * </fileset>
+ * </pre>
+ *
+ */
+public class BundleHTMLExtractorTask extends Task {
+
+ private Vector filesets = new Vector();
+ private FileUtils fileUtils;
+
+ private File templateHTMLDir = new File(".");
+ private String listSeparator = "<br>\n";
+ private File baseDir = new File(".");
+ private String javadocRelPath = null;
+
+
+ private String indexListRow =
+ "<a target=\"bundle_main\" href=\"${bundledoc}\">${FILE.short}</a><br>";
+
+ private String indexMainRow =
+ "<tr>" +
+ "<td><a target=\"bundle_main\" href=\"${bundledoc}\">${FILE.short}</a></td><td>" +
+ "<td>${Bundle-Description}</td>" +
+ "</tr>\n";
+
+ private String bundleRow =
+ "<tr><td><a href=\"${bundledoc}\">${FILE.short}</a></td><td>${what}</td></tr>\n";
+
+ private String missingRow =
+ "<tr><td>${name}</td><td>${version}</td></tr>\n";
+
+ private String rowHTML =
+ "<a href=\"${bundle.uri}\">${FILE.short}</a><br>\n";
+
+ private String pkgHTML =
+ "${namelink} ${version}<br>";
+
+ private boolean bCheckJavaDoc = true;
+
+ Map jarMap = new TreeMap();
+ Map globalVars = new TreeMap();
+
+
+ Map missingDocs = new TreeMap();
+
+ public BundleHTMLExtractorTask() {
+
+ fileUtils = FileUtils.newFileUtils();
+
+ setListProps("Export-Package," +
+ "Import-Package," +
+ "Import-Service," +
+ "Export-Service");
+
+ setSystemPackageSet("javax.swing," +
+ "javax.accessibility," +
+ "javax.servlet," +
+ "javax.xml," +
+ "org.xml," +
+ "org.w3c," +
+ "java," +
+ "com.sun");
+
+ setSkipAttribSet("Manifest-Version," +
+ "Ant-Version," +
+ "Bundle-Config," +
+ "Created-By"
+ // "Built-From",
+ );
+
+ setAlwaysProps("Bundle-Activator," +
+ "Bundle-Vendor," +
+ "Bundle-Name," +
+ "Bundle-Description," +
+ "Export-Package," +
+ "Import-Package," +
+ "Import-Service," +
+ "Export-Service," +
+ "Main-class," +
+ "Build-Date," +
+ "Bundle-DocURL," +
+ "Bundle-Classpath," +
+ "Bundle-ContactAddress," +
+ "Bundle-Activator");
+ }
+
+ public void setCheckJavaDoc(String s) {
+ this.bCheckJavaDoc = "true".equals(s);
+ }
+
+ public void setTemplateHTMLDir(String s) {
+ this.templateHTMLDir = new File(s);
+
+ if(!templateHTMLDir.exists()) {
+ throw new BuildException("templateHTMLDir: " + s + " does not exist");
+ }
+ if(!templateHTMLDir.isDirectory()) {
+ throw new BuildException("templateHTMLDir: " + s + " is not a directory");
+ }
+ }
+
+
+ File getBundleInfoTemplate() {
+ return new File(templateHTMLDir, "bundle_info.html");
+ }
+
+ File getBundleCSSTemplate() {
+ return new File(templateHTMLDir, "style.css");
+ }
+
+ File getBundleListTemplate() {
+ return new File(templateHTMLDir, "bundle_list.html");
+ }
+
+ File getBundleMainTemplate() {
+ return new File(templateHTMLDir, "bundle_main.html");
+ }
+
+ File getBundleIndexTemplate() {
+ return new File(templateHTMLDir, "bundle_index.html");
+ }
+
+ public void setBaseDir(String s) {
+ this.baseDir = new File((new File(s)).getAbsolutePath());
+ }
+
+ public void setJavadocRelPath(String s) {
+ this.javadocRelPath = s;
+ }
+
+ public void addFileset(FileSet set) {
+ filesets.addElement(set);
+ }
+
+ Set listPropSet = new HashSet();
+ Set skipAttribSet = new HashSet();
+ Set alwaysPropSet = new HashSet();
+ Set systemPackageSet = new HashSet();
+
+ public void setListProps(String s) {
+ listPropSet = Util.makeSetFromStringList(s);
+ }
+
+ public void setAlwaysProps(String s) {
+ alwaysPropSet = Util.makeSetFromStringList(s);
+ }
+
+ public void setSkipAttribSet(String s) {
+ skipAttribSet = Util.makeSetFromStringList(s);
+ }
+
+ public void setSystemPackageSet(String s) {
+ systemPackageSet = Util.makeSetFromStringList(s);
+ }
+
+ // Implements Task
+ public void execute() throws BuildException {
+ if (filesets.size() == 0) {
+ throw new BuildException("No fileset specified");
+ }
+
+ try {
+ for (int i = 0; i < filesets.size(); i++) {
+ FileSet fs = (FileSet) filesets.elementAt(i);
+ DirectoryScanner ds = fs.getDirectoryScanner(project);
+ File projDir = fs.getDir(project);
+
+ String[] srcFiles = ds.getIncludedFiles();
+ String[] srcDirs = ds.getIncludedDirectories();
+
+ for (int j = 0; j < srcFiles.length ; j++) {
+ File file = new File(projDir, srcFiles[j]);
+ if(file.getName().endsWith(".jar")) {
+ jarMap.put(file, new BundleInfo(file));
+ }
+ }
+ }
+
+ System.out.println("analyzing " + jarMap.size() + " bundles");
+
+ for(Iterator it = jarMap.keySet().iterator(); it.hasNext();) {
+ File file = (File)it.next();
+ BundleInfo info = (BundleInfo)jarMap.get(file);
+
+ info.load();
+ }
+
+ System.out.println("writing bundle info html pages");
+ for(Iterator it = jarMap.keySet().iterator(); it.hasNext();) {
+ File file = (File)it.next();
+ BundleInfo info = (BundleInfo)jarMap.get(file);
+
+ info.writeInfo();
+ }
+
+ makeListPage(getBundleMainTemplate(),
+ new File(baseDir, "main.html"),
+ indexMainRow);
+
+ makeListPage(getBundleListTemplate(),
+ new File(baseDir, "list.html"),
+ indexListRow);
+
+ copyFile(getBundleIndexTemplate(),
+ new File(baseDir, "index.html"));
+
+ copyFile(getBundleCSSTemplate(),
+ new File(baseDir, "style.css"));
+
+
+ for(Iterator it = missingDocs.keySet().iterator(); it.hasNext();) {
+ String name = (String)it.next();
+
+ System.out.println("Missing javadoc for " + name);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new BuildException("Failed to extract bundle info: " + e, e);
+ }
+ }
+
+ void makeListPage(File templateFile,
+ File outFile,
+ String rowTemplate)
+ throws IOException {
+
+ int unresolvedCount = 0;
+
+ String html = Util.loadFile(templateFile.getAbsolutePath());
+
+ StringBuffer sb = new StringBuffer();
+ for(Iterator it = jarMap.keySet().iterator(); it.hasNext();) {
+ File file = (File)it.next();
+ BundleInfo info = (BundleInfo)jarMap.get(file);
+
+ unresolvedCount += info.unresolvedMap.size();
+
+ String row = rowTemplate;
+
+ row = info.stdReplace(row, false);
+
+ row = replace(row,
+ "${bundledoc}",
+ replace(info.path, ".jar", ".html"));
+
+ sb.append(row);
+ }
+
+
+
+ html = replace(html, "${bundle.list}", sb.toString());
+
+ sb = new StringBuffer();
+
+ if(unresolvedCount > 0) {
+
+ sb.append("<table>\n");
+ sb.append("<tr>\n" +
+ " <td colspan=2 class=\"mfheader\">Unresolved packages</td>\n" +
+ "</tr>\n");
+
+ for(Iterator it = jarMap.keySet().iterator(); it.hasNext();) {
+ File file = (File)it.next();
+ BundleInfo info = (BundleInfo)jarMap.get(file);
+
+ if(info.unresolvedMap.size() > 0) {
+ sb.append("<tr>\n" +
+ " <td>" + info.file.getName() + "</td>\n");
+
+ sb.append("<td>");
+ for(Iterator it2 = info.unresolvedMap.keySet().iterator();
+ it2.hasNext();)
+ {
+ String pkgName = (String)it2.next();
+ ArrayInt version = (ArrayInt)info.unresolvedMap.get(pkgName);
+
+ sb.append(pkgName + " " + version + "<br>\n");
+ }
+ sb.append("</td>");
+ sb.append("<tr>");
+ }
+ }
+ sb.append("</table>\n");
+ }
+
+ html = replace(html, "${unresolved.list}", sb.toString());
+
+
+
+
+
+ Util.writeStringToFile(outFile, html);
+ System.out.println("wrote " + outFile);
+
+ }
+
+ void copyFile(File templateFile, File outFile)
+ throws IOException {
+
+ String src = Util.loadFile(templateFile.getAbsolutePath());
+
+ Util.writeStringToFile(outFile, src);
+ System.out.println("copied " + outFile);
+ }
+
+ interface MapSelector {
+ public Map getMap(BundleInfo info);
+ }
+
+
+ class BundleInfo {
+ File file;
+ Attributes attribs;
+ Map vars = new TreeMap();
+
+ // String (package name) -> ArrayInt (version)
+ Map pkgImportMap = new TreeMap();
+ Map pkgExportMap = new TreeMap();
+ Map serviceExportMap = new TreeMap();
+ Map serviceImportMap = new TreeMap();
+
+ String relPath = "";
+ String path = "";
+
+ Map unresolvedMap = new TreeMap();
+
+ public BundleInfo(File file) throws IOException {
+ this.file = file;
+ relPath = "";
+ File dir = file.getParentFile();
+
+ while(dir != null && !dir.equals(baseDir)) {
+ // System.out.println("** ! " + dir + " || " + baseDir);
+ relPath += "../";
+ dir = dir.getParentFile();
+
+ }
+
+ if(dir == null) {
+ throw new BuildException(baseDir.getAbsolutePath() + " is not parent of " + file.getAbsolutePath());
+ }
+
+ if(relPath.equals("")) {
+ // relPath = ".";
+ }
+
+
+ path = replace(file.getCanonicalPath().substring(1 + baseDir.getCanonicalPath().length()), "\\", "/");
+
+ // System.out.println(file + ", " + relPath + ", " + baseDir.getAbsolutePath() + ", path=" + path);
+ }
+
+ public void load() throws Exception {
+ JarFile jarFile = new JarFile(file);
+ Manifest mf = jarFile.getManifest();
+ attribs = mf.getMainAttributes();
+
+ vars.put("html.file", replace(file.toString(), ".jar", ".html"));
+
+ String absBase = baseDir.getCanonicalPath();
+
+ String htmlFilename = (String)vars.get("html.file");
+
+ File htmlFile = new File(htmlFilename);
+
+ String absFile = htmlFile.getCanonicalPath();
+
+ if(!absFile.startsWith(absBase)) {
+ System.out.println("*** base dir is not parent of html file");
+ System.out.println("base dir: " + absBase);
+ System.out.println("html file: " + absFile);
+ } else {
+ String relPath = absFile.substring(absBase.length() + 1);
+
+ // System.out.println("absFile=" + absFile);
+ // System.out.println("relPath=" + relPath);
+
+ vars.put("html.uri", replace(relPath, "\\", "/"));
+ }
+
+ pkgExportMap = parseNames(attribs.getValue("Export-Package"));
+ pkgImportMap = parseNames(attribs.getValue("Import-Package"));
+ serviceExportMap = parseNames(attribs.getValue("Export-Service"));
+ serviceImportMap = parseNames(attribs.getValue("Import-Service"));
+
+ if(true) {
+ extractSource(jarFile, new File(replace(file.getAbsolutePath(), ".jar", "") + "/src"));
+ }
+ }
+
+
+ // String -> String
+ Map sourceMap = new TreeMap();
+ boolean bSourceInside = false;
+
+ void extractSource(JarFile jarFile, File destDir) throws IOException {
+
+ String prefix = "OSGI-OPT/src";
+
+ int count = 0;
+ for(Enumeration e = jarFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry entry = (ZipEntry)e.nextElement();
+
+ if(entry.getName().startsWith("OSGI-OPT/src")) {
+ count++;
+ }
+ }
+
+
+ if(count > 0) {
+ bSourceInside = true;
+
+ // System.out.println("found " + count + " source files in " + jarFile.getName());
+
+ // System.out.println("creating "+ destDir.getAbsolutePath());
+ destDir.mkdirs();
+
+ for(Enumeration e = jarFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry entry = (ZipEntry)e.nextElement();
+
+ if(entry.getName().startsWith(prefix)) {
+ if(entry.isDirectory()) {
+ makeDir(jarFile, entry, destDir, prefix);
+ } else {
+ copyEntry(jarFile, entry, destDir, prefix);
+
+ String s = replace(entry.getName(), prefix + "/", "");
+ sourceMap.put(s, s);
+ }
+ count++;
+ }
+ }
+
+ } else {
+ // Check if we can copy source from original pos
+ String sourceDir = (String)attribs.getValue("Built-From");
+ if(sourceDir != null && !"".equals(sourceDir)) {
+ File src = new File(sourceDir, "src");
+ copyTree(src, destDir, sourceDir + "\\src\\", ".java");
+ }
+ }
+ }
+
+ void copyTree(File src, File dest,
+ String prefix,
+ String suffix) throws IOException {
+ if(src.isDirectory()) {
+ if(!dest.exists()) {
+ dest.mkdirs();
+ }
+
+ String[] files = src.list();
+ for(int i = 0; i < files.length; i++) {
+ copyTree(new File(src, files[i]),
+ new File(dest, files[i]),
+ prefix,
+ suffix);
+ }
+ } else if(src.isFile()) {
+ if(src.getName().endsWith(suffix)) {
+ String path = src.getAbsolutePath();
+
+ String s = replace(replace(path, prefix, ""), "\\", "/");
+
+ copyStream(new FileInputStream(src), new FileOutputStream(dest));
+ sourceMap.put(s, s);
+ }
+ }
+ }
+
+
+ void makeDir(ZipFile file,
+ ZipEntry entry,
+ File destDir,
+ String prefix) throws IOException {
+ File d = new File(destDir, replace(entry.getName(), prefix, ""));
+
+ d.mkdirs();
+ // System.out.println("created dir " + d.getAbsolutePath());
+ }
+
+
+ void copyEntry(ZipFile file,
+ ZipEntry entry,
+ File destDir,
+ String prefix) throws IOException {
+ File d = new File(destDir, replace(entry.getName(), prefix, ""));
+
+ File dir = d.getParentFile();
+
+ if(!dir.exists()) {
+ dir.mkdirs();
+ }
+
+ // System.out.println("extracting to " + d.getAbsolutePath());
+
+ copyStream(new BufferedInputStream(file.getInputStream(entry)),
+ new BufferedOutputStream(new FileOutputStream(d)));
+ }
+
+
+ void copyStream(InputStream is, OutputStream os) throws IOException {
+ byte[] buf = new byte[1024];
+
+
+ BufferedInputStream in = null;
+ BufferedOutputStream out = null;
+
+ try {
+ in = new BufferedInputStream(is);
+ out = new BufferedOutputStream(os);
+ int n;
+ int total = 0;
+ while ((n = in.read(buf)) > 0) {
+ out.write(buf, 0, n);
+ total += n;
+ }
+ } finally {
+ try { in.close(); } catch (Exception ignored) { }
+ try { out.close(); } catch (Exception ignored) { }
+ }
+ }
+
+
+
+ Map parseNames(String s) {
+
+ Map map = new TreeMap();
+
+ // System.out.println(file + ": " + s);
+ if(s != null) {
+ s = s.trim();
+ String[] lines = Util.splitwords(s, ",", '\"');
+ for(int i = 0; i < lines.length; i++) {
+ String[] words = Util.splitwords(lines[i].trim(), ";", '\"');
+ if(words.length < 1) {
+ throw new RuntimeException("bad package spec '" + s + "'");
+ }
+ String spec = ArrayInt.UNDEF;
+ String name = words[0].trim();
+
+ for(int j = 1; j < words.length; j++) {
+ String[] info = Util.splitwords(words[j], "=", '\"');
+
+ if(info.length == 2) {
+ if("specification-version".equals(info[0].trim())) {
+ spec = info[1].trim();
+ }
+ }
+ }
+
+ // System.out.println(" " + i + ": " + name + ", version=" + spec);
+ ArrayInt version = new ArrayInt(spec);
+
+ map.put(name, version);
+ }
+ }
+
+ return map;
+ }
+
+ public void writeInfo() throws IOException {
+
+ // System.out.println("jar info from " + file);
+
+ String template = stdReplace(Util.load(getBundleInfoTemplate().getAbsolutePath()));
+ String outName = (String)vars.get("html.file");
+
+ Util.writeStringToFile(new File(outName), template);
+ }
+
+ public String stdReplace(String template) throws IOException {
+ return stdReplace(template, true);
+ }
+
+
+ public String stdReplace(String template, boolean bDepend) throws IOException {
+
+ for(Iterator it = globalVars.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Object val = globalVars.get(key);
+
+ template = replace(template, "${" + key + "}", "" + val);
+
+ // System.out.println(key + "->" + val);
+ }
+
+ for(Iterator it = vars.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Object val = vars.get(key);
+
+ template = replace(template, "${" + key + "}", "" + val);
+
+ // System.out.println(key + "->" + val);
+ }
+
+ Set handledSet = new TreeSet();
+
+ for(Iterator it = attribs.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+
+ if(-1 != template.indexOf("${" + key.toString() + "}")) {
+ handledSet.add(key.toString());
+ }
+ }
+
+ for(Iterator it = attribs.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+ Object val = attribs.get(key);
+
+
+ String str = (String)attribs.get(key);
+
+ if("Export-Package".equals(key.toString()) ||
+ "Import-Package".equals(key.toString()) ||
+ "Import-Service".equals(key.toString()) ||
+ "Export-Service".equals(key.toString())) {
+ } else {
+ if(listPropSet.contains(key.toString())) {
+ str = replace(str, ",", listSeparator);
+ }
+
+ template = replace(template, "${" + key + "}", str);
+ }
+ }
+
+
+ template = replace(template,
+ "${Export-Package}",
+ getPackageString(pkgExportMap,
+ "/package-summary.html"));
+
+ template = replace(template,
+ "${Import-Package}",
+ getPackageString(pkgImportMap,
+ "/package-summary.html"));
+
+
+ template = replace(template,
+ "${Export-Service}",
+ getPackageString(serviceExportMap,
+ ".html"));
+
+ template = replace(template,
+ "${Import-Service}",
+ getPackageString(serviceImportMap,
+ ".html"));
+
+
+ for(Iterator it = alwaysPropSet.iterator(); it.hasNext(); ) {
+ String key = (String)it.next();
+ String val = "";
+
+ template = replace(template, "${" + key + "}", val);
+ }
+
+ StringBuffer sb = new StringBuffer();
+
+ for(Iterator it = attribs.keySet().iterator(); it.hasNext(); ) {
+ Object key = it.next();
+
+ if(!handledSet.contains(key.toString())) {
+ if(!skipAttribSet.contains(key.toString())) {
+ sb.append("<tr>\n" +
+ " <td>" + key + "</td>\n" +
+ " <td>" + attribs.getValue(key.toString()) + "</td>\n" +
+ "</tr>\n");
+ }
+ }
+ }
+
+ template = replace(template, "${MF.UNHANDLED}", sb.toString());
+
+ template = replace(template, "${FILE}", file.getName());
+ template = replace(template, "${FILE.short}", replace(file.getName(), ".jar", ""));
+ template = replace(template, "${BYTES}", "" + file.length());
+ template = replace(template, "${KBYTES}", "" + (file.length() / 1024));
+
+ template = replace(template, "${relpath}", relPath);
+ template = replace(template, "${javadocdir}",
+ javadocRelPath != null ? javadocRelPath : "");
+
+
+ if(bDepend) {
+ unresolvedMap = new TreeMap();
+
+ template = replace(template,
+ "${depending.list}",
+ getDepend(
+ new MapSelector() {
+ public Map getMap(BundleInfo info) {
+ return info.pkgExportMap;
+ }
+ },
+ new MapSelector() {
+ public Map getMap(BundleInfo info) {
+ return info.pkgImportMap;
+ }
+ },
+ null,
+ false));
+
+ template = replace(template,
+ "${depends.list}",
+ getDepend(
+ new MapSelector() {
+ public Map getMap(BundleInfo info) {
+ return info.pkgImportMap;
+ }
+ },
+ new MapSelector() {
+ public Map getMap(BundleInfo info) {
+ return info.pkgExportMap;
+ }
+ },
+ unresolvedMap,
+ true));
+
+ }
+
+ sb = new StringBuffer();
+ if(sourceMap.size() > 0) {
+
+ String srcBase = replace(file.getName(), ".jar", "") + "/src";
+
+ sb.append("<table>");
+ for(Iterator it = sourceMap.keySet().iterator(); it.hasNext();) {
+ String name = (String)it.next();
+
+
+ sb.append(" <tr>\n");
+ sb.append(" <td>\n");
+ sb.append(" <a href=\"" + srcBase + "/" + name + "\">" + name + "<a>\n");
+ sb.append(" </tr>\n");
+ sb.append(" </tr>\n");
+
+ }
+ sb.append("</table>");
+
+ } else{
+ sb.append("None found");
+ }
+
+ template = replace(template, "${sources.list}", sb.toString());
+ if(bSourceInside && sourceMap.size() > 0) {
+ template = replace(template,
+ "${FILEINFO}",
+ file.length() + " bytes, includes <a href=\"#source\">source</a>");
+ } else {
+ template = replace(template,
+ "${FILEINFO}",
+ file.length() + " bytes");
+ }
+
+
+ return template;
+ }
+
+
+ String getDepend(MapSelector importMap,
+ MapSelector exportMap,
+ Map unresolvedMapDest,
+ boolean bShowUnresolved) throws IOException {
+
+ Map map = new TreeMap();
+
+ if(unresolvedMapDest == null) {
+ unresolvedMapDest = new TreeMap();
+ }
+
+ for(Iterator it = importMap.getMap(this).keySet().iterator(); it.hasNext(); ) {
+ String name = (String)it.next();
+ ArrayInt version = (ArrayInt)importMap.getMap(this).get(name);
+
+ boolean bFound = false;
+ for(Iterator it2 = jarMap.keySet().iterator(); it2.hasNext();) {
+ File jarFile = (File)it2.next();
+ BundleInfo info = (BundleInfo)jarMap.get(jarFile);
+
+ for(Iterator it3 = exportMap.getMap(info).keySet().iterator(); it3.hasNext(); ) {
+ String name2 = (String)it3.next();
+ ArrayInt version2 = (ArrayInt)exportMap.getMap(info).get(name);
+
+ if(name.equals(name2)) {
+ if(version2.compareTo(version) >= 0) {
+ bFound = true;
+ map.put(jarFile, name);
+ } else {
+ System.out.println(file + ": need " + name + " version " + version + ", found version " + version2);
+ }
+ }
+ }
+ }
+
+ if(!bFound && !isSystemPackage(name)) {
+ unresolvedMapDest.put(name, version);
+ }
+
+ }
+ StringBuffer sb = new StringBuffer();
+
+ if(map.size() == 0 && unresolvedMapDest.size() == 0) {
+ sb.append("None found");
+ } else {
+ for(Iterator it = map.keySet().iterator(); it.hasNext();) {
+ Object key = it.next();
+ File jarFile = (File)key;
+ BundleInfo info = (BundleInfo)jarMap.get(jarFile);
+ String what = (String)map.get(jarFile);
+
+ String row = info.stdReplace(bundleRow, false);
+
+ row = replace(row, "${what}", what);
+ row = replace(row,
+ "${bundledoc}",
+ replace(relPath + info.path, ".jar", ".html"));
+ sb.append(row);
+ }
+
+
+ if(bShowUnresolved) {
+ if(unresolvedMapDest.size() > 0) {
+ String row = missingRow;
+
+ row = replace(row, "${name}", "<b>Unresolved</b>");
+ row = replace(row, "${version}", "");
+
+ sb.append(row);
+ }
+ for(Iterator it = unresolvedMapDest.keySet().iterator(); it.hasNext();) {
+ String name = (String)it.next();
+ ArrayInt version = (ArrayInt)unresolvedMapDest.get(name);
+
+ String row = missingRow;
+
+ row = replace(row, "${name}", name);
+ row = replace(row, "${version}", version.toString());
+
+ sb.append(row);
+
+ }
+ }
+
+ }
+ return sb.toString();
+ }
+
+
+
+ String getPackageString(Map map, String linkSuffix) {
+ StringBuffer sb = new StringBuffer();
+
+ for(Iterator it = map.keySet().iterator(); it.hasNext(); ) {
+ String name = (String)it.next();
+ ArrayInt version = (ArrayInt)map.get(name);
+
+ String html = pkgHTML;
+
+ String docFile = replace(name, ".", "/") + linkSuffix;
+ String docPath = relPath + javadocRelPath + "/" + docFile;
+
+ File f = new File(file.getParentFile(), docPath);
+
+
+ if(javadocRelPath != null && !"".equals(javadocRelPath)) {
+ if(bCheckJavaDoc && !f.exists() && !isSystemPackage(name)) {
+ html = replace(html, "${namelink}", "${name}");
+
+ missingDocs.put(name, this);
+ } else {
+ html = replace(html,
+ "${namelink}", "<a href=\"${javadoc}\">${name}</a>");
+ }
+ } else {
+ html = replace(html, "${namelink}", "${name}");
+ }
+
+ String row = replace(html, "${name}", name);
+
+ row = replace(row, "${version}", version.toString());
+ row = replace(row, "${javadoc}", docPath);
+
+ sb.append(row);
+ }
+
+ return sb.toString();
+ }
+ }
+
+
+ boolean isSystemPackage(String name) {
+ for(Iterator it = systemPackageSet.iterator(); it.hasNext();) {
+ String prefix = (String)it.next();
+ if(name.startsWith(prefix)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ String replace(String src, String a, String b) {
+ return Util.replace(src, a, b == null ? "" : b);
+ }
+
+
+}
+
+
Added: cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleInfoTask.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleInfoTask.java?rev=189461&view=auto
==============================================================================
--- cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleInfoTask.java (added)
+++ cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleInfoTask.java Tue Jun 7 15:32:48 2005
@@ -0,0 +1,788 @@
+/*
+ * Copyright (c) 2003, KNOPFLERFISH 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 KNOPFLERFISH 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER OR 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.knopflerfish.ant.taskdefs.bundle;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.classfile.*;
+import org.apache.bcel.generic.Type;
+import org.apache.bcel.generic.BasicType;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Task that analyzes a set of java sources or class files, and lists all
+ * imported and defined packages. Also tries to find any class implementing
+ * <tt>org.osgi.framework.BundleActivator</tt>.
+ *
+ * <ul>
+ * <li><b>Class files</b>
+ * <p>
+ * Java class files are analyzed using the BCEL lib available from
+ * <a href="http://jakarta.apache.org/bcel">http://jakarta.apache.org/bcel</a>.
+ * <br>
+ * <b>Note</b>: Scanning <i>only</i> applies
+ * to the listed files - a complete closure of all referenced classes is
+ * not done.
+ * </p>
+ *
+ * <li><b>Source code</b>
+ * <p>
+ * Java source code is analyzed using very simple line-based scanning of
+ * files. <br>
+ * <b>Note</b>: Source code analysis does not attempt to find any
+ * <tt>BundleActivator</tt>
+ * </p>
+ *
+ * <li><b>Jar files</b>
+ * <p>
+ * Jar file analysis is not yet implemented
+ * </p>
+ *
+ * </ul>
+ *
+ * <h3>Parameters</h3>
+ *
+ * <table border=>
+ * <tr>
+ * <td valign=top><b>Attribute</b></td>
+ * <td valign=top><b>Description</b></td>
+ * <td valign=top><b>Required</b></td>
+ * </tr>
+ * <tr>
+ * <td valign=top>imports</td>
+ * <td valign=top>Name of property that will receive a comma-separated list
+ * of all used packages.
+ * <p>
+ * If set to empty string, no property will be set.
+ * </p>
+ * <p>
+ * <b>Note</b>: Some default packages are always added. These
+ * defaults can be set using the <tt>defaultimports</tt> parameter.
+ * </p>
+ * </td>
+ * <td valign=top>No.<br> Default value is ""</td>
+ * </tr>
+ * <tr>
+ * <td valign=top>exports</td>
+ * <td valign=top>Name of property that will receive a comma-separated
+ * list of all defined packages.
+ * <p>
+ * If set to empty string, no property will be set.
+ * </p>
+ * </td>
+ * <td valign=top>No.<br> Default value is ""</td>
+ * </tr>
+ * <td valign=top>activator</td>
+ * <td valign=top>
+ * Name of property that will receive name of class which implements
+ * <tt>org.osgi.framework.BundleActivator</tt>
+ * <p>
+ * If set to empty string, no property will be set.
+ * </p>
+ * <p>
+ * If set to non-empty, and multiple activators are found, or
+ * an activator not equal to any previous content in the named property
+ * is found - a warning will be logged.
+ * </p>
+ * </td>
+ * <td valign=top>No.<br> Default value is ""</td>
+ * </tr>
+ * <tr>
+ * <td valign=top>stdimports</td>
+ * <td valign=top>
+ * Comma-separated list of all prefixes to standard packages that
+ * should be ignored in exports list.
+ * </td>
+ * <td valign=top>
+ * No.<br>
+ * Default value is "java."
+ * </td>
+ * </tr>
+ *
+ * <tr>
+ * <td valign=top>defaultimports</td>
+ * <td valign=top>
+ * Comma-separated list of all default imported packages.
+ * <p>
+ * <b>Note</b>: Do not set <tt>defaultimports</tt> to the empty
+ * string, since that might
+ * cause an later illegal bundle manifest file if <i>no</i> imported
+ * packages are found.
+ * </p>
+ * </td>
+ * <td valign=top>
+ * No.<br>
+ * Default value is "org.osgi.framework"
+ * </td>
+ * </tr>
+ *
+ * <tr>
+ * <td valign=top>checkFoundationEE</td>
+ * <td valign=top>
+ * Flag for testing for the Foundation Execution Environment
+ * <p>
+ * If set to "true", the task will check if all used classes
+ * is in the set of the OSGi Foundation Execution Environment.
+ * </p>
+ * </td>
+ * <td valign=top>
+ * No.<br>
+ * Default value is "false"
+ * </td>
+ * </tr>
+ *
+ * <h3>Parameters specified as nested elements</h3>
+ * <h4>fileset</h4>
+ *
+ * (required)<br>
+ * <p>
+ * All files must be specified as a fileset. Unsupported file types
+ * are ignored.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ *
+ * <h4>Check all imports and activator in implementation classes</h4>
+ *
+ * <p>
+ * This example assumes all implemention classes are in the package
+ * <tt>test.impl.*</tt>
+ * </p>
+ *
+ * <pre>
+ * <bundleinfo activator = "bundle.activator"
+ * imports = "impl.import.package">
+ * <fileset dir="classes" includes="test/impl/*"/>
+ * </bundleinfo>
+ * <echo message="imports = ${impl.import.package}"/>
+ * <echo message="activator = ${bundle.activator}"/>
+ * </pre>
+ *
+ *
+ * <h4>Check all imports and exports in API classes</h4>
+ *
+ * <p>
+ * This example assumes all API classes are in the package
+ * <tt>test.*</tt>
+ * </p>
+ *
+ * <pre>
+ * <bundleinfo exports = "api.export.package"
+ * imports = "api.import.package">
+ * <fileset dir="classes" includes="test/*"/>
+ * </bundleinfo>
+ * <echo message="imports = ${api.import.package}"/>
+ * <echo message="exports = ${api.export.package}"/>
+ * </pre>
+ *
+ */
+public class BundleInfoTask extends Task {
+
+ private Vector filesets = new Vector();
+ private FileUtils fileUtils;
+
+ private String importsProperty = "";
+ private String exportsProperty = "";
+ private String activatorProperty = "";
+ private String mainProperty = "";
+
+ private Set stdImports = new TreeSet();
+ private boolean bDebug = false;
+
+ private boolean bPrintClasses = false;
+
+ private boolean bCheckFoundationEE = false;
+ private boolean bCheckMinimumEE = false;
+ private boolean bCheckSMFEE = false;
+
+ private Set importSet = new TreeSet();
+ private Set exportSet = new TreeSet();
+ private Set activatorSet = new TreeSet();
+
+ private Set classSet = new TreeSet();
+ private Set ownClasses = new TreeSet();
+
+ public BundleInfoTask() {
+ fileUtils = FileUtils.newFileUtils();
+ setDefaultImports("org.osgi.framework");
+ setStdImports("java.");
+ }
+
+ /**
+ * Set property receiving list of imported packages.
+ */
+ public void setImports(String s) {
+ this.importsProperty = s;
+ }
+
+ public void setPrintClasses(String s) {
+ this.bPrintClasses = "true".equals(s);
+ }
+
+ public void setCheckFoundationEE(String s) {
+ this.bCheckFoundationEE = "true".equals(s);
+ }
+
+ public void setCheckMinimumEE(String s) {
+ this.bCheckMinimumEE = "true".equals(s);
+ }
+
+ public void setCheckSMFEE(String s) {
+ this.bCheckSMFEE = "true".equals(s);
+ }
+
+ /**
+ * Set default import set.
+ *
+ * @param packageList Comma-separated list of package names.
+ */
+ public void setDefaultImports(String packageList) {
+ Vector v = StringUtils.split(packageList.trim(),',');
+ importSet.clear();
+ importSet.addAll(v);
+ }
+
+
+ /**
+ * Set property receiving list of exported packages.
+ */
+ public void setExports(String propName) {
+ this.exportsProperty = propName;
+ }
+
+ /**
+ * Set property receiving any BundleActivator class.
+ */
+ public void setActivator(String propName) {
+ this.activatorProperty = propName;
+ }
+
+ /**
+ * Set property receiving any Main class.
+ * <p>
+ * Not yet implemented.
+ * </p>
+ */
+ public void setMain(String propName) {
+ this.mainProperty = propName;
+ }
+
+
+ /**
+ * Set set of packages always imported.
+ *
+ * @param packageList Comma-separated list of package names.
+ */
+ public void setStdImports(String packageList) {
+ stdImports.clear();
+ stdImports.addAll(StringUtils.split(packageList.trim(),','));
+ }
+
+ public void addFileset(FileSet set) {
+ filesets.addElement(set);
+ }
+
+ // Implements Task
+ //
+ // Scan all files in fileset and delegate to analyze()
+ // then write back values to properties.
+ public void execute() throws BuildException {
+ if (filesets.size() == 0) {
+ throw new BuildException("No fileset specified");
+ }
+
+ for (int i = 0; i < filesets.size(); i++) {
+ FileSet fs = (FileSet) filesets.elementAt(i);
+ DirectoryScanner ds = fs.getDirectoryScanner(project);
+ File fromDir = fs.getDir(project);
+
+ String[] srcFiles = ds.getIncludedFiles();
+ String[] srcDirs = ds.getIncludedDirectories();
+
+ for (int j = 0; j < srcFiles.length ; j++) {
+ analyze(new File(fromDir, srcFiles[j]));
+ }
+
+ for (int j = 0; j < srcDirs.length ; j++) {
+ analyze(new File(fromDir, srcDirs[j]));
+ }
+ }
+
+ // Scan done - write back properties
+
+ Project proj = getProject();
+
+ importSet.removeAll(exportSet);
+
+ if(!"".equals(importsProperty)) {
+ proj.setNewProperty(importsProperty, toString(importSet, ","));
+ }
+
+ if(!"".equals(exportsProperty)) {
+ proj.setNewProperty(exportsProperty, toString(exportSet, ","));
+ }
+
+ // Try to be a bit clever when writing back bundle activator
+ if(!"".equals(activatorProperty)) {
+ switch(activatorSet.size()) {
+ case 0:
+ System.out.println("info - no class implementing " +
+ "BundleActivator found");
+ break;
+ case 1:
+ {
+ String clazz = (String)activatorSet.iterator().next();
+ String clazz0 = proj.getProperty(activatorProperty);
+ if(clazz0 == null || "".equals(clazz0)) {
+ // System.out.println("set activator " + activatorProperty + "=" + clazz);
+ } else {
+ if(!clazz.equals(clazz0)) {
+ System.out.println("*** Warning - the class found implementing " +
+ " BundleActivator '" + clazz + "' " +
+ " does not match the one set as " +
+ activatorProperty + "=" + clazz0);
+ } else {
+ if(bDebug) {
+ System.out.println("correct activator " +
+ activatorProperty + "=" + clazz0);
+ }
+ }
+ }
+ proj.setNewProperty(activatorProperty, clazz);
+ }
+ break;
+ default:
+ System.out.println("*** Warning - more than one class " +
+ "implementing BundleActivator found:");
+ for(Iterator it = activatorSet.iterator(); it.hasNext();) {
+ System.out.println(" " + it.next());
+ }
+ break;
+
+ }
+ }
+
+ Set foundationMissing = new TreeSet();
+ Set minimumMissing = new TreeSet();
+ Set smfMissing = new TreeSet();
+
+
+ for(Iterator it = classSet.iterator(); it.hasNext();) {
+ String s = (String)it.next();
+ if(s.endsWith("[]")) {
+ } else {
+ if(!ownClasses.contains(s)) {
+ if(bPrintClasses) {
+ System.out.println(s);
+ }
+ if(!EE.isFoundation(s)) {
+ if(!isImported(s)) {
+ foundationMissing.add(s);
+ }
+ }
+ if(!EE.isMinimum(s)) {
+ if(!isImported(s)) {
+ minimumMissing.add(s);
+ }
+ }
+ if(!EE.isSMF(s)) {
+ if(!isImported(s)) {
+ smfMissing.add(s);
+ }
+ }
+ }
+ }
+ }
+
+ if(bCheckFoundationEE) {
+ if(foundationMissing.size() > 0) {
+ System.out.println("Missing " + foundationMissing.size() +
+ " classes from foundation profile");
+ } else {
+ System.out.println("Passes foundation EE");
+ }
+ for(Iterator it = foundationMissing.iterator(); it.hasNext();) {
+ String s = (String)it.next();
+ System.out.println("Not in foundation: " + s);
+ }
+ }
+
+ if(bCheckMinimumEE) {
+ if(minimumMissing.size() > 0) {
+ System.out.println("Missing " + minimumMissing.size() +
+ " classes from minimum profile");
+ } else {
+ System.out.println("Passes minimum EE");
+ }
+ for(Iterator it = minimumMissing.iterator(); it.hasNext();) {
+ String s = (String)it.next();
+ System.out.println("Not in minimum: " + s);
+ }
+ }
+
+ if(bCheckSMFEE) {
+ if(smfMissing.size() > 0) {
+ System.out.println("Missing " + smfMissing.size() +
+ " classes from SMF profile");
+ } else {
+ System.out.println("Passes SMF EE");
+ }
+ for(Iterator it = smfMissing.iterator(); it.hasNext();) {
+ String s = (String)it.next();
+ System.out.println("Not in SMF: " + s);
+ }
+ }
+ }
+
+
+
+
+ /**
+ * Analyze a file by checking its suffix and delegate to
+ * <tt>analyzeClass</tt>, <tt>analyzeJava</tt> etc
+ */
+ protected void analyze(File file) throws BuildException {
+ if(file.getName().endsWith(".class")) {
+ analyzeClass(file);
+ } else if(file.getName().endsWith(".java")) {
+ analyzeJava(file);
+ } else {
+ // Just ignore all other files
+ }
+ }
+
+
+ protected void addExportedPackageString(String name) {
+ if(name == null || "".equals(name)) {
+ return;
+ }
+
+ if(bDebug) {
+ System.out.println(" package " + name);
+ }
+ exportSet.add(name);
+ }
+
+
+ protected void addActivatorString(String s) {
+ activatorSet.add(s);
+ }
+
+ /**
+ * Add a type's package name to the list of imported packages.
+ *
+ * @param t Type of an object.
+ */
+ protected void addImportedType(Type t) {
+ if(t instanceof BasicType) {
+ // Ignore all basic types
+ } else {
+ addImportedString(t.toString());
+ }
+ }
+
+ /**
+ * Add a class' package name to the list of imported packages.
+ *
+ * @param className Class name of an object. The class name is stripped
+ * from the part after the last '.' and added to set
+ * of imported packages, if its not one of the standard
+ * packages. Primitive class names are ignore.
+ */
+ protected void addImportedString(String className) {
+
+ if(className == null) {
+ return;
+ }
+
+ String name = packageName(className);
+
+ if("".equals(name)) {
+ return;
+ }
+
+ // only add packages defined outside this set of files
+ if(!exportSet.contains(name)) {
+
+ // ...and only add non-std packages
+ if(!isStdImport(name)) {
+ importSet.add(name);
+ }
+ }
+
+ classSet.add(className);
+ }
+
+ boolean isImported(String className) {
+ for(Iterator it = importSet.iterator(); it.hasNext(); ) {
+ String pkg = (String)it.next();
+ if(className.startsWith(pkg)) {
+ String rest = className.substring(pkg.length() + 1);
+ if(-1 == rest.indexOf(".")) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if package is included in prefix list of standard packages.
+ *
+ * @return <tt>true</tt> if name is prefixed with any of the elements in
+ * <tt>stdImports</tt> set, <tt>false</tt> otherwise.
+ */
+ protected boolean isStdImport(String name) {
+ for(Iterator it = stdImports.iterator(); it.hasNext();) {
+ String s = (String)it.next();
+ if(name.startsWith(s)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ protected void analyzeJar(File file) throws BuildException {
+ throw new BuildException("Jar file analyzing not yet supported");
+ }
+
+ protected void analyzeClass(File file) throws BuildException {
+ if(bDebug) {
+ System.out.println("Analyze class file " + file.getAbsolutePath());
+ }
+
+ try {
+ ClassParser parser = new ClassParser(file.getAbsolutePath());
+ final JavaClass clazz = parser.parse();
+ final ConstantPool constant_pool = clazz.getConstantPool();
+
+ ownClasses.add(clazz.getClassName());
+
+ DescendingVisitor v = new DescendingVisitor(clazz, new EmptyVisitor() {
+
+
+ // Delegate all ConstantCP calls to visitConstantCP()
+ public void visitConstantFieldRef(ConstantFieldref obj) {
+ visitConstantCP(obj);
+ }
+ public void visitConstantMethodref(ConstantMethodref obj) {
+ visitConstantCP(obj);
+ }
+ public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj) {
+ visitConstantCP(obj);
+ }
+
+ // Extract information from method calls found
+ // in constant table
+ // This information is used to get all imported packages
+ private void visitConstantCP(ConstantCP obj) {
+
+ // This is amazingly complex - isn't there any
+ // easier way to get the referenced class names???
+
+ int signature_ix = obj.getNameAndTypeIndex();
+ int class_ix = obj.getClassIndex();
+
+ ConstantNameAndType c = (ConstantNameAndType)
+ constant_pool.getConstant(signature_ix,
+ Constants.CONSTANT_NameAndType);
+
+ ConstantClass cc = (ConstantClass)
+ constant_pool.getConstant(class_ix,
+ Constants.CONSTANT_Class);
+
+ // Whoa!! This is the name of the called object's class
+ String objType = Utility.compactClassName(((ConstantUtf8)constant_pool.getConstant(cc.getNameIndex(), Constants.CONSTANT_Utf8)).getBytes(), false);
+
+
+ String sig = c.getSignature(constant_pool);
+ String name = c.getName(constant_pool);
+
+ String retType = Utility.methodSignatureReturnType(sig);
+ String[] argTypes = Utility.methodSignatureArgumentTypes(sig);
+
+ for(int i = 0; i < argTypes.length; i++) {
+ addImportedString(argTypes[i]);
+ }
+
+ addImportedString(retType);
+ addImportedString(objType);
+ }
+
+
+ // This information is used to get all imported packages,
+ // as well as extracting the class package name for exported
+ // packages.
+ public void visitJavaClass(JavaClass obj) {
+
+ addExportedPackageString(obj.getPackageName());
+
+ addImportedString(obj.getSuperclassName());
+
+ // Scan all implemented interfaces to find
+ // candidates for the activator AND to find
+ // all referenced packages.
+ String[] interfaces = obj.getInterfaceNames();
+ for(int i = 0; i < interfaces.length; i++) {
+ addImportedString(interfaces[i]);
+ if("org.osgi.framework.BundleActivator".equals(interfaces[i])) {
+ addActivatorString(obj.getClassName());
+ }
+ }
+ }
+
+ // hmmm...this should already be found in constant pool
+ public void visitLocalVariable(LocalVariable obj) {
+ Type type = Type.getType(obj.getSignature());
+
+ addImportedType(type);
+ }
+
+
+ // this too should be found in constant pool.
+ // But I'm really unsure.
+ public void visitMethod(Method obj) {
+ addImportedType(obj.getReturnType());
+
+ Type[] argv = obj.getArgumentTypes();
+
+ for(int i = 0; i < argv.length; i++) {
+ addImportedType(argv[i]);
+ }
+ }
+
+ });
+
+ // Run the scanner on the loaded class
+ v.visit();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new BuildException("Failed to parse .class file " +
+ file + ", exception=" + e);
+ }
+ }
+
+ /**
+ * Analyze java source file by reading line by line and looking
+ * for keywords such as "import", "package".
+ *
+ * <p>
+ * <b>Note</b>: This code does not attempt to find any class implementing
+ * <tt>BundleActivator</tt>
+ */
+ protected void analyzeJava(File file) throws BuildException {
+
+ if(bDebug) {
+ System.out.println("Analyze java file " + file.getAbsolutePath());
+ }
+
+ BufferedReader reader = null;
+
+ try {
+ String line;
+ int lineNo = 0;
+
+ reader = new BufferedReader(new FileReader(file));
+
+ while(null != (line = reader.readLine())) {
+ lineNo++;
+ line = line.replace(';', ' ').replace('\t', ' ').trim();
+
+ if(line.startsWith("package")) {
+ Vector v = StringUtils.split(line, ' ');
+ if(v.size() > 1 && "package".equals(v.elementAt(0))) {
+ String name = (String)v.elementAt(1);
+ addExportedPackageString(name);
+ }
+ }
+ if(line.startsWith("import")) {
+ Vector v = StringUtils.split(line, ' ');
+ if(v.size() > 1 && "import".equals(v.elementAt(0))) {
+ String name = (String)v.elementAt(1);
+ addImportedString(name);
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new BuildException("Failed to scan " + file + ", err=" + e);
+ } finally {
+ if(reader != null) {
+ try { reader.close(); } catch (Exception ignored) { }
+ }
+ }
+ }
+
+ /**
+ * Get package name of class string representation.
+ */
+ static String packageName(String s) {
+ s = s.trim();
+ int ix = s.lastIndexOf('.');
+ if(ix != -1) {
+ s = s.substring(0, ix);
+ } else {
+ s = "";
+ }
+ return s;
+ }
+
+ /**
+ * Convert Set elements to a string.
+ *
+ * @param separator String to use as sperator between elements.
+ */
+ static protected String toString(Set set, String separator) {
+ StringBuffer sb = new StringBuffer();
+
+ for(Iterator it = set.iterator(); it.hasNext(); ) {
+ String name = (String)it.next();
+ sb.append(name);
+ if(it.hasNext()) {
+ sb.append(separator);
+ }
+ }
+ return sb.toString();
+ }
+}
Added: cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleManifestTask.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleManifestTask.java?rev=189461&view=auto
==============================================================================
--- cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleManifestTask.java (added)
+++ cocoon/whiteboard/osgi/ant/src/org/knopflerfish/ant/taskdefs/bundle/BundleManifestTask.java Tue Jun 7 15:32:48 2005
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003, KNOPFLERFISH 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 KNOPFLERFISH 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER OR 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.knopflerfish.ant.taskdefs.bundle;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Manifest;
+import org.apache.tools.ant.taskdefs.ManifestTask;
+import org.apache.tools.ant.taskdefs.ManifestException;
+
+
+/**
+ * Adaption of std Manifest task which ignores attributes
+ * with special empty values.
+ *
+ * <p>
+ * Any attrubute with the value
+ * <pre>
+ * [bundle.emptystring]
+ * </pre>
+ * will <b>not</b> be stored in the manifest at all.
+ * </p>
+ */
+public class BundleManifestTask extends ManifestTask {
+ public BundleManifestTask() {
+ super();
+ }
+
+ /**
+ * Override <tt>ManifestTask.addConfiguredAttribute</tt> with
+ * version which checks if the attribute should be stored.
+ */
+ public void addConfiguredAttribute(Manifest.Attribute attribute)
+ throws ManifestException {
+ if("[bundle.emptystring]".equals(attribute.getValue())) {
+ return;
+ }
+ super.addConfiguredAttribute(attribute);
+ }
+
+}