/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.build; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.GZip; import org.apache.tools.ant.taskdefs.Jar; import org.apache.tools.ant.taskdefs.Manifest; import org.apache.tools.ant.types.FileSet; import org.jnode.build.packager.PluginListInsertor; import org.jnode.plugin.PluginDescriptor; import org.jnode.plugin.PluginException; import org.jnode.plugin.PluginPrerequisite; import org.jnode.plugin.model.PluginJar; /** * @author Ewout Prangsma (epr@users.sourceforge.net) */ public class InitJarBuilder extends AbstractPluginsTask { private File destDir; private File destFile; private PluginListInsertor insertor; public void execute() throws BuildException { final long start = System.currentTimeMillis(); final PluginList piList; final PluginList systemPluginList; final long lmPI; try { piList = getPluginList(); if (insertor != null) { insertor.insertInto(piList); } systemPluginList = getSystemPluginList(); if ((destFile == null) && (destDir != null)) { destFile = new File(destDir, piList.getName() + ".jgz"); } lmPI = Math.max(piList.lastModified(), systemPluginList.lastModified()); } catch (PluginException ex) { throw new BuildException(ex); } catch (IOException ex) { throw new BuildException(ex); } final long lmDest = destFile.lastModified(); final long lmPIL = getPluginListFile().lastModified(); if ((lmPIL < lmDest) && (lmPI < lmDest)) { // No need to do anything, skip return; } destFile.delete(); final File tmpFile = new File(destFile + ".tmp"); tmpFile.delete(); try { // Load the plugin descriptors /* * final PluginRegistry piRegistry; piRegistry = new * PluginRegistryModel(piList.getDescriptorUrlList()); */ final Jar jarTask = new Jar(); jarTask.setProject(getProject()); jarTask.setTaskName(getTaskName()); jarTask.setDestFile(tmpFile); jarTask.setCompress(false); final Manifest mf = piList.getManifest(); if (mf != null) { jarTask.addConfiguredManifest(mf); } final URL[] systemPlugins = systemPluginList.getPluginList(); final ArrayList<PluginJar> pluginJars = new ArrayList<PluginJar>(); for (URL url : systemPlugins) { final BuildPluginJar piJar = new BuildPluginJar(url); if (!piJar.getDescriptor().isSystemPlugin()) { log("Non-system plugin " + piJar.getDescriptor().getId() + " in plugin-list will be ignored", Project.MSG_WARN); } else { pluginJars.add(piJar); } } final URL[] pluginList = piList.getPluginList(); for (URL url : pluginList) { final BuildPluginJar piJar = new BuildPluginJar(url); if (piJar.getDescriptor().isSystemPlugin()) { log("System plugin " + piJar.getDescriptor().getId() + " in plugin-list will be ignored", Project.MSG_WARN); } else { pluginJars.add(piJar); } } testPluginPrerequisites(pluginJars); final List<PluginJar> sortedPluginJars = sortPlugins(pluginJars); for (Iterator<PluginJar> i = sortedPluginJars.iterator(); i .hasNext();) { final BuildPluginJar piJar = (BuildPluginJar) i.next(); if (!piJar.getDescriptor().isSystemPlugin()) { // pluginJars.add(piJar); final File f = new File(piJar.getPluginUrl().getPath()); final FileSet fs = new FileSet(); fs.setDir(f.getParentFile()); fs.setIncludes(f.getName()); jarTask.addFileset(fs); } } /* * for (Iterator i = piRegistry.getDescriptorIterator(); * i.hasNext(); ) { final PluginDescriptor descr = * (PluginDescriptor)i.next(); final Runtime rt = * descr.getRuntime(); if (rt != null) { final Library[] libs = * rt.getLibraries(); for (int l = 0; l < libs.length; l++) { * processLibrary(jarTask, libs[l], fileSets, getPluginDir()); } } */ // Now create the jar file jarTask.execute(); // Now zip it final GZip gzipTask = new GZip(); gzipTask.setProject(getProject()); gzipTask.setTaskName(getTaskName()); gzipTask.setSrc(tmpFile); gzipTask.setZipfile(destFile); gzipTask.execute(); tmpFile.delete(); } catch (Exception ex) { ex.printStackTrace(); throw new BuildException(ex); } final long end = System.currentTimeMillis(); log("Building initjar took " + (end - start) + "ms"); } /** * @param file */ public void setDestFile(File file) { destFile = file; } /** * Ensure that all plugin prerequisites are met. * * @throws BuildException */ protected void testPluginPrerequisites(List<PluginJar> pluginJars) throws BuildException { final Map<String, List<String>> idToVersions = new HashMap<String, List<String>>(); // get all couples (id, version) in idToVersions for (PluginJar piJar : pluginJars) { final PluginDescriptor descr = piJar.getDescriptor(); List<String> versions = idToVersions.get(descr.getId()); if (versions == null) { versions = new ArrayList<String>(); idToVersions.put(descr.getId(), versions); } versions.add(descr.getVersion().toString()); } // now, check that each dependency is satisfied for (PluginJar piJar : pluginJars) { final PluginDescriptor descr = piJar.getDescriptor(); final PluginPrerequisite[] prereqs = descr.getPrerequisites(); for (int j = 0; j < prereqs.length; j++) { PluginPrerequisite required = prereqs[j]; List<String> versions = idToVersions.get(required.getPluginReference().getId()); boolean versionSpecified = (required.getPluginReference().getVersion() == null); boolean satisfied = false; if (versions != null) { satisfied = !versionSpecified || versions.contains(required.getPluginReference().getVersion().toString()); } if (!satisfied) { String reqVersionStr = versionSpecified ? "" : " version " + required.getPluginReference().getVersion(); String versionStr = (descr.getVersion() == null) ? "" : " version " + descr.getVersion(); throw new BuildException("Cannot find plugin " + required.getPluginReference().getId() + reqVersionStr + ", which is required by " + descr.getId() + versionStr); } } } } /** * Sort the plugins based on dependencies. * * @param pluginJars */ protected List<PluginJar> sortPlugins(List<PluginJar> pluginJars) { final ArrayList<PluginJar> result = new ArrayList<PluginJar>(pluginJars.size()); final HashSet<String> ids = new HashSet<String>(); while (!pluginJars.isEmpty()) { boolean somethingRemoved = false; for (Iterator<PluginJar> i = pluginJars.iterator(); i.hasNext();) { final BuildPluginJar piJar = (BuildPluginJar) i.next(); if (piJar.hasAllPrerequisitesInSet(ids)) { log(piJar.getDescriptor().getId(), Project.MSG_VERBOSE); result.add(piJar); ids.add(piJar.getDescriptor().getId()); i.remove(); somethingRemoved = true; } } if (!somethingRemoved) { StringBuilder sb = new StringBuilder("cycle in plugin dependencies :\n"); for (Iterator<PluginJar> i = pluginJars.iterator(); i.hasNext();) { final BuildPluginJar piJar = (BuildPluginJar) i.next(); sb.append(piJar.getDescriptor().getId()).append('\n'); } throw new BuildException(sb.toString()); } } return result; } static class BuildPluginJar extends PluginJar { private final URL pluginUrl; /** * @param pluginUrl * @throws PluginException * @throws IOException */ BuildPluginJar(URL pluginUrl) throws PluginException, IOException { super(null, pluginUrl); this.pluginUrl = pluginUrl; } /** * @return Returns the pluginUrl. */ final URL getPluginUrl() { return this.pluginUrl; } public boolean hasAllPrerequisitesInSet(Set<String> ids) { final PluginDescriptor descr = getDescriptor(); final PluginPrerequisite[] prereqs = descr.getPrerequisites(); for (int j = 0; j < prereqs.length; j++) { if (!ids.contains(prereqs[j].getPluginReference().getId())) { return false; } } return true; } } /** * @return Returns the destDir. */ public final File getDestDir() { return destDir; } /** * @param destDir The destDir to set. */ public final void setDestDir(File destDir) { this.destDir = destDir; } public void setPackager(PluginListInsertor insertor) { this.insertor = insertor; } }