/* ==================================================================== * * The ObjectStyle Group Software License, Version 1.0 * * Copyright (c) 2002 - 2005 The ObjectStyle Group * and individual authors of the software. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. 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. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * ObjectStyle Group (http://objectstyle.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "ObjectStyle Group" and "Cayenne" * must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact andrus@objectstyle.org. * * 5. Products derived from this software may not be called "ObjectStyle" * nor may "ObjectStyle" appear in their names without prior written * permission of the ObjectStyle Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 OBJECTSTYLE GROUP OR * ITS 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. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the ObjectStyle Group. For more * information on the ObjectStyle Group, please see * <http://objectstyle.org/>. * */ package org.objectstyle.woproject.ant; import java.io.File; import java.io.IOException; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.FileScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.PropertyHelper; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.PatternSet; import org.apache.tools.ant.types.PatternSet.NameEntry; import org.objectstyle.woenvironment.env.WOVariables; import org.objectstyle.woenvironment.frameworks.ExternalFolderFramework; import org.objectstyle.woenvironment.frameworks.ExternalFolderRoot; import org.objectstyle.woenvironment.frameworks.ExternalFrameworkModel; import org.objectstyle.woenvironment.frameworks.FrameworkLibrary; import org.objectstyle.woenvironment.frameworks.IFramework; import org.objectstyle.woenvironment.frameworks.Root; import org.w3c.dom.Node; /** * A subclass of FileSet that with special support for matching WOFrameworks. * * @author Andrei Adamchik */ public class FrameworkSet extends FileSet { private Root<IFramework> root; private ExternalFrameworkModel frameworkModel; private boolean eclipse; private boolean embed; private boolean hasBundles; private boolean frameworkIncludesCreated; private File deploymentDir; private String ifCondition; /** * Creates new FrameworkSet. */ public FrameworkSet() { ifCondition = ""; } public void setEclipse(boolean eclipse) { this.eclipse = eclipse; } public boolean getEclipse() { return this.eclipse; } public void setFrameworkModel(ExternalFrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; } @SuppressWarnings("unchecked") public ExternalFrameworkModel getFrameworkModel() { if (this.frameworkModel == null) { this.frameworkModel = new ExternalFrameworkModel(getProject().getProperties()); } return this.frameworkModel; } /** * Sets the deployment root directory (can be different from the normal * <code>root</code> specified). The idea is that you can specify the * compile time path via <code>dir=/some_binary_release_path/</code>, but * still end up with <code>LOCALROOT/Library/Frameworks/Bar.framework</code> * as the prefix. * * @param root */ public void setDeploymentDir(File root) { this.deploymentDir = root; } public void setBundles(String value) { String bundles[] = value.split("/"); PatternSet ps = createPatternSet(); for (int i = 0; i < bundles.length; i++) { String framework = bundles[i]; if (framework.trim().length() > 0) { hasBundles = true; framework = framework + ".framework"; ps.createInclude().setName(framework); } } } protected File getDeployedFile(File file) { File result = file; if (this.deploymentDir != null && !getEmbed()) { // maps // foo/bar/Baz.framework/Resources/Java/xxx.jar -> // /System/Library/Frameworks/Baz.framework String oldPath = file.getPath(); String newRoot = deploymentDir.getPath(); String newPath = oldPath.replaceFirst("(.*?)(/\\w+\\.framework/)", newRoot + "$2"); result = new File(newPath); } return result; } protected void setFrameworkRoot(ExternalFolderRoot root) { this.root = root; } protected Root<IFramework> getFrameworkRoot() { if (this.root == null) { ExternalFrameworkModel currentFrameworkModel = getFrameworkModel(); try { this.root = currentFrameworkModel.getRootForFolder(getDir()); } catch (IOException e) { throw new BuildException("There was no matching framework root found for the folder '" + getDir() + "'. The known framework roots are " + currentFrameworkModel.getRoots() + ".", e); } } return this.root; } /** * Sets root directory of this FileSet based on a symbolic name, that can be * "User", "Local", "System". Throws BuildException if an * invalid root is specified. */ public void setRoot(String rootName) throws BuildException { ExternalFrameworkModel currentFrameworkModel = getFrameworkModel(); this.root = currentFrameworkModel.getRootWithShortName(rootName); if (this.root == null) { throw new BuildException("There is no root named '" + rootName + "' in " + currentFrameworkModel.getRoots() + "."); } File rootFolder = ((ExternalFolderRoot) this.root).getFrameworksFolder(); setDir(rootFolder); } protected List<ExternalFolderFramework> getEclipseFrameworks() { try { List<ExternalFolderFramework> frameworks = new LinkedList<ExternalFolderFramework>(); List<Node> conEntries = FileUtil.getClasspathEntriesOfKind(getProject().getBaseDir(), "con"); for (Node conEntry : conEntries) { Node pathAttribute = conEntry.getAttributes().getNamedItem("path"); String path = pathAttribute.getTextContent(); if (path != null && path.startsWith("WOFramework/")) { int slashIndex = path.indexOf("/"); String frameworkName = path.substring(slashIndex + 1); IFramework framework = this.frameworkModel.getFrameworkWithName(frameworkName); if (framework == null) { throw new BuildException("The framework name '" + frameworkName + "' does not exist."); } else if (framework instanceof ExternalFolderFramework && framework.getRoot() == this.root) { ExternalFolderFramework externalFolderFramework = (ExternalFolderFramework) framework; frameworks.add(externalFolderFramework); } } } return frameworks; } catch(BuildException e) { throw e; } catch (Throwable t) { throw new BuildException("Failed to process eclipse frameworks: "+t.getMessage(), t); } } @Override public synchronized void setupDirectoryScanner(FileScanner ds, Project p) { if (this.eclipse && !frameworkIncludesCreated) { try { List<ExternalFolderFramework> frameworks = getEclipseFrameworks(); for (ExternalFolderFramework framework : frameworks) { NameEntry frameworkInclude = createInclude(); frameworkInclude.setName(framework.getFrameworkFolder().getName()); } // If no frameworks are to be included from this directory, create an // empty include. Setting a name or using an exclude will throw Ant into // an infinite loop. if (frameworks.isEmpty()) { NameEntry frameworkExclude = createInclude(); } frameworkIncludesCreated = true; } catch (Throwable t) { throw new BuildException("Failed to process eclipse frameworks: "+t.getMessage(), t); } } super.setupDirectoryScanner(ds, p); } public void setEmbed(boolean flag) { this.embed = flag; } public boolean getEmbed() { if (isReference() && getProject() != null) { return ((FrameworkSet) getRef(getProject())).getEmbed(); } return this.embed; } public void setIf(String string) { ifCondition = string == null ? "" : string; } protected Path getJarsPath() { Path frameworkPath = new Path(getProject()); List<ExternalFolderFramework> frameworks; if (getEclipse()) { frameworks = getEclipseFrameworks(); } else { frameworks = new LinkedList<ExternalFolderFramework>(); String[] includedFrameworkFolderNames = getDirectoryScanner(getProject()).getIncludedDirectories(); for (String includedFrameworkFolderName : includedFrameworkFolderNames) { String frameworkName = ExternalFolderFramework.frameworkNameForFolder(new File(includedFrameworkFolderName)); if (frameworkName != null) { if (getDir() == null) { IFramework framework = getFrameworkModel().getFrameworkWithName(frameworkName); if (framework instanceof ExternalFolderFramework) { frameworks.add((ExternalFolderFramework) framework); } } else { ExternalFolderFramework framework = new ExternalFolderFramework(getFrameworkRoot(), new File(getDir(), includedFrameworkFolderName)); frameworks.add(framework); } } else { System.out.println("FrameworkSet.getJarsPath: ILLEGAL FRAMEWORK NAMED " + frameworkName); } } } for (IFramework framework : frameworks) { if (framework.getRoot() == null || framework.getRoot().equals(getFrameworkRoot())) { for (FrameworkLibrary frameworkLibrary : framework.getFrameworkLibraries()) { File jarFile = frameworkLibrary.getLibraryFile(); File deployedJarFile = getDeployedFile(jarFile); //log(": Framework JAR " + jarFile, Project.MSG_VERBOSE); frameworkPath.setLocation(deployedJarFile); } } else { //System.out.println("FrameworkSet.getJarsPath: SKIPPED FRAMEWORK " + framework + " (" + includedFrameworkName + ") for " + getFrameworkRoot()); } } return frameworkPath; } public static Path jarsPathForFrameworkSets(Project project, List<FrameworkSet> frameworkSets, WOVariables variables) { List<AntDependency> unorderedDependencies = new LinkedList<AntDependency>(); for (FrameworkSet frameworkSet : frameworkSets) { Path jarsPath = frameworkSet.getJarsPath(); for (String jarPath : jarsPath.list()) { unorderedDependencies.add(new AntDependency(frameworkSet, jarPath, variables)); } } List<AntDependency> orderedDependencies = new AntDependencyOrdering().orderDependencies(unorderedDependencies); Path path = new Path(project); for (AntDependency dependency : orderedDependencies) { String jarPath = dependency.getJarPath(); path.append(new Path(project, jarPath)); } //System.out.println("FrameworkSet.jarsPathForFrameworkSets1: <" + path + ">"); return path; } public static String jarsPathForFrameworkSets(Project project, String relativeEmbeddedFrameworksDir, List<FrameworkSet> frameworkSets, WOVariables variables) { List<AntDependency> unorderedDependencies = new LinkedList<AntDependency>(); for (FrameworkSet frameworkSet : frameworkSets) { Path jarsPath = frameworkSet.getJarsPath(); for (String jarPath : jarsPath.list()) { unorderedDependencies.add(new AntDependency(frameworkSet, jarPath, variables)); } } StringBuffer path = new StringBuffer(); List<AntDependency> orderedDependencies = new AntDependencyOrdering().orderDependencies(unorderedDependencies); for (AntDependency dependency : orderedDependencies) { String jarPath = dependency.getJarPath(); String encodedPath = variables.encodePath(jarPath); FrameworkSet frameworkSet = dependency.getFrameworkSet(); if (frameworkSet.getEmbed()) { String prefix = frameworkSet.getDir(project).getAbsolutePath(); prefix = variables.encodePath(prefix); if (frameworkSet.hasBundles()) { encodedPath = encodedPath.replaceFirst(".*?(\\w+.framework)", "APPROOT/" + relativeEmbeddedFrameworksDir + "/$1"); } else { encodedPath = encodedPath.replaceFirst(prefix, "APPROOT/" + relativeEmbeddedFrameworksDir); } } path.append(encodedPath).append(System.getProperty("line.separator")); } //System.out.println("FrameworkSet.jarsPathForFrameworkSets2: <" + path + ">"); return path.toString(); } private boolean hasBundles() { return hasBundles; } @Override public DirectoryScanner getDirectoryScanner(Project p) { if (getDir() == null || !getDir().exists()) { DirectoryScanner scanner = new DirectoryScanner() { @Override public synchronized String[] getIncludedDirectories() { return new String[0]; } @Override public synchronized int getIncludedDirsCount() { return 0; } @Override public synchronized String[] getIncludedFiles() { return new String[0]; } @Override public synchronized int getIncludedFilesCount() { return 0; } }; return scanner; } return super.getDirectoryScanner(p); } private static String replaceProperties(Project project, String value, Hashtable keys) throws BuildException { PropertyHelper ph = PropertyHelper.getPropertyHelper(project); return ph.replaceProperties(null, value, keys); } private boolean testIfCondition() { if ("".equals(ifCondition)) { return true; } String string = FrameworkSet.replaceProperties(getProject(), ifCondition, getProject().getProperties()); return getProject().getProperty(string) != null; } @Override public String toString() { return "[FrameworkSet: root = " + getDir() + "]"; } // /** // * Overrides the super method in order to return the right DirectoryScanner // * that doesn't sort directories. See svn revision detail: // * http://svn.apache.org/viewcvs.cgi?rev=274976&view=rev // * // * Instead sort by the order defined in the include list. // */ // @Override // public DirectoryScanner getDirectoryScanner(Project p) { // DirectoryScanner ds = super.getDirectoryScanner(p); // if (isReference()) { // return ds; // } // // Setup a new type for the directory scanner to avoid sorting included // // directories as set by: // // http://svn.apache.org/viewcvs.cgi?rev=274976&view=rev // // but rather sort by order of the includes list. // ds = new SortedDirectoryScanner(); // setupDirectoryScanner(ds, p); // ds.setFollowSymlinks(isFollowSymlinks()); // ds.scan(); // return ds; // } // protected class SortedDirectoryScanner extends DirectoryScanner implements Comparator { // private List<String> includeNonPatternList; // // @SuppressWarnings("unchecked") // @Override // public synchronized String[] getIncludedDirectories() { // if (dirsIncluded == null) { // throw new IllegalStateException(); // } // if (includeNonPatternList == null) { // includeNonPatternList = new ArrayList<String>(); // fillNonPatternList(includeNonPatternList, includes); // } // Collections.sort(dirsIncluded, this); // String directories[] = new String[dirsIncluded.size()]; // dirsIncluded.copyInto(directories); // return directories; // } // // @Override // public synchronized String[] getIncludedFiles() { // // The results of calling jarsPaths() on the FrameworkSet is a // // fully qualified path. This creates a problem as FileSet qualifies // // these file paths with the directory. To accomodate this, we // // trim off the root dir. This will be added back after getIncludedFiles() // // is called. This (hack) was done instead of making a parallel // // implementation of jarsPath() that returns a partial path. // String[] frameworkJars = getJarsPath().list(); // int dirLength = getDir(getProject()).toString().length(); // for (int i = 0; i < frameworkJars.length; i++) { // frameworkJars[i] = frameworkJars[i].substring(dirLength); // } // // // The included files are both the normally included files as well as // // the jars in the frameworks // String[] files = super.getIncludedFiles(); // String[] all = new String[files.length + frameworkJars.length]; // System.arraycopy(files, 0, all, 0, files.length); // System.arraycopy(frameworkJars, 0, all, files.length, frameworkJars.length); // // return all; // } // // public int compare(Object o1, Object o2) { // String frameworkDir1 = (String) o1; // String frameworkDir2 = (String) o2; // if (isCaseSensitive()) { // return includeNonPatternList.indexOf(frameworkDir1) - includeNonPatternList.indexOf(frameworkDir2); // } // return includeNonPatternList.indexOf(frameworkDir1.toUpperCase()) - includeNonPatternList.indexOf(frameworkDir2.toUpperCase()); // } // // @SuppressWarnings("unchecked") // private String[] fillNonPatternList(List list, String patterns[]) { // System.out.println("SortedDirectoryScanner.fillNonPatternList: " + list + ", " + patterns); // ArrayList<String> al = new ArrayList<String>(patterns.length); // for (int i = 0; i < patterns.length; i++) // if (!SelectorUtils.hasWildcards(patterns[i])) { // list.add(isCaseSensitive() ? ((Object) (patterns[i])) : ((Object) (patterns[i].toUpperCase()))); // } // else { // al.add(patterns[i]); // } // // return list.size() != 0 ? (String[]) al.toArray(new String[al.size()]) : patterns; // } // // } }