/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o 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, see http://www.gnu.org/licenses/. */ package com.db4o.instrumentation.ant; import java.io.*; import java.util.*; import java.util.jar.*; import org.apache.tools.ant.*; import org.apache.tools.ant.types.*; import org.apache.tools.ant.types.resources.*; import com.db4o.instrumentation.classfilter.*; import com.db4o.instrumentation.core.*; import com.db4o.instrumentation.file.*; import com.db4o.instrumentation.main.*; /** * Ant task for build time class file instrumentation. * * @see BloatClassEdit */ public class Db4oFileEnhancerAntTask extends Task { private final List<FileSet> _sources = new ArrayList<FileSet>(); private File _targetDir; private final List<Path> _classPath = new ArrayList<Path>(); private final List<AntClassEditFactory> _editFactories = new ArrayList<AntClassEditFactory>(); private final List<FileSet> _jars = new ArrayList<FileSet>(); private File _jarTargetDir; private boolean _verbose = false; public void add(AntClassEditFactory editFactory) { _editFactories.add(editFactory); } public void addSources(FileSet fileSet) { _sources.add(fileSet); } public void addJars(FileSet fileSet) { _jars.add(fileSet); } public void setClassTargetDir(File targetDir) { _targetDir = targetDir; } public void setJarTargetdir(File targetDir) { _jarTargetDir=targetDir; } public void setVerbose(boolean verbose) { _verbose = verbose; } public void addClasspath(Path path) { _classPath.add(path); } public void execute() { try { FileSet[] sourceArr = _sources.toArray(new FileSet[_sources.size()]); AntFileSetPathRoot root = new AntFileSetPathRoot(sourceArr); ClassFilter filter = collectClassFilters(root); BloatClassEdit clazzEdit = collectClassEdits(filter); final String[] classPath = collectClassPath(); enhanceClassFiles(root, clazzEdit, classPath); enhanceJars(clazzEdit, classPath); } catch (Exception exc) { throw new BuildException(exc); } } private static interface FileResourceBlock { void process(FileResource resource) throws Exception; } private String[] collectClassPath() throws Exception { final List<String> paths=new ArrayList<String>(); for (Path path : _classPath) { String[] curPaths=path.list(); for (String curPath : curPaths) { paths.add(curPath); } } forEachResource(_jars, new FileResourceBlock() { public void process(FileResource resource) throws Exception { paths.add(resource.getFile().getCanonicalPath()); } }); for (FileSet fileSet : _sources) { paths.add(fileSet.getDir().getCanonicalPath()); } return paths.toArray(new String[paths.size()]); } private void enhanceClassFiles(AntFileSetPathRoot root, BloatClassEdit clazzEdit, final String[] classPath) throws Exception { logClassFiles(root); new Db4oFileInstrumentor(clazzEdit).enhance(root, _targetDir, classPath); } private void enhanceJars(BloatClassEdit clazzEdit, final String[] classPath) throws Exception { final Db4oJarEnhancer jarEnhancer = new Db4oJarEnhancer(clazzEdit); forEachResource(_jars, new FileResourceBlock() { public void process(FileResource resource) throws Exception { File targetJarFile = new File(_jarTargetDir, resource.getFile().getName()); verboseLog("Enhancing jar: " + targetJarFile.getAbsolutePath()); jarEnhancer.enhance(resource.getFile(), targetJarFile, classPath); } }); } private ClassFilter collectClassFilters(AntFileSetPathRoot root) throws Exception { final List<ClassFilter> filters = new ArrayList<ClassFilter>(); filters.add(root); forEachResource(_jars, new FileResourceBlock() { public void process(FileResource resource) throws IOException { JarFile jarFile = new JarFile(resource.getFile()); filters.add(new JarFileClassFilter(jarFile)); } }); ClassFilter filter = new CompositeOrClassFilter(filters.toArray(new ClassFilter[filters.size()])); return filter; } @SuppressWarnings("unchecked") private void forEachResource(List<FileSet> fileSets, FileResourceBlock collectFiltersBlock) throws Exception { for (FileSet fileSet : fileSets) { for (Iterator<FileResource> resourceIter = fileSet.iterator(); resourceIter.hasNext();) { FileResource fileResource = resourceIter.next(); collectFiltersBlock.process(fileResource); } } } private BloatClassEdit collectClassEdits(ClassFilter classFilter) { BloatClassEdit clazzEdit = null; switch(_editFactories.size()) { case 0: clazzEdit = new NullClassEdit(); break; case 1: clazzEdit = _editFactories.get(0).createEdit(classFilter); break; default: List<BloatClassEdit> classEdits = new ArrayList<BloatClassEdit>(_editFactories.size()); for (AntClassEditFactory curFactory : _editFactories) { classEdits.add(curFactory.createEdit(classFilter)); } clazzEdit = new CompositeBloatClassEdit(classEdits.toArray(new BloatClassEdit[classEdits.size()]), true); } return clazzEdit; } private void verboseLog(String msg) { if(_verbose) { log(msg, Project.MSG_INFO); } } private void logClassFiles(AntFileSetPathRoot root) throws IOException { verboseLog("Enhancing class files."); verboseLog("Target folder: " + _targetDir.getAbsolutePath()); verboseLog("Root folders:"); for (String rootStr : root.rootDirs()) { verboseLog(new File(rootStr).getAbsolutePath()); } verboseLog("Files:"); for (Iterator<InstrumentationClassSource> fileSetIter = root.iterator(); fileSetIter.hasNext();) { verboseLog(fileSetIter.next().toString()); } } }