/* * Copyright 2009 Alexis Wilhelm, Romain Tertiaux. This program is free * software: you can do anything, but lay off of my blue suede shoes. */ package com.izforge.izpack.installer; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.Properties; import java.util.zip.ZipInputStream; import com.izforge.izpack.IPSPack; import com.izforge.izpack.LocaleDatabase; import com.izforge.izpack.util.AbstractUIProgressHandler; import com.sun.pkg.client.ExtendedImage; import com.sun.pkg.client.ImagePlanProgressTracker; import com.sun.pkg.client.Image.FmriState; import com.sun.pkg.client.Image.ImagePlan; /** * An unpacker for the IPS packs. * * @author Alexis Wilhelm * @author Romain Tertiaux * @since January 2009 */ public class IPSUnpacker extends UnpackerBase { /** * Some callbacks useful for trackje faactions performed * by {@link ImagePlan#execute(ImagePlanProgressTracker)}. */ private static class ImagePlanProgressTrackerForIzPack extends ImagePlanProgressTracker { /** * The installation progress handler. */ private final AbstractUIProgressHandler handler; /** * The localized strings. */ private final LocaleDatabase lang; /** * The current step within the current job. */ private int step; /** * Initialize this tracker. * * @param handler The installation progress handler. * @param lang The localized strings. * @param step The current step. */ public ImagePlanProgressTrackerForIzPack ( AbstractUIProgressHandler handler, LocaleDatabase lang, int step) { this.handler = handler; this.step = step; this.lang = lang; } /** * {@inheritDoc} */ @Override public void startDownloadPhase (int total) { handler.progress(++step, lang.getString(this, "startDownloadPhase", total, total > 1 ? "s" : "")); } /** * {@inheritDoc} */ @Override public void startInstallPhase (int total) { handler.progress(++step, lang.getString(this, "startInstallPhase", total, total > 1 ? "s" : "")); } /** * {@inheritDoc} */ @Override public void startRemovalPhase (int total) { handler.progress(++step, lang.getString(this, "startRemovalPhase", total, total > 1 ? "s" : "")); } /** * {@inheritDoc} */ @Override public void startUpdatePhase (int total) { handler.progress(++step, lang.getString(this, "startUpdatePhase", total, total > 1 ? "s" : "")); } } /** * The name for the empty IPS image in this installer's resource set. */ public static final String TEMPLATE = "ips/empty.zip"; /** * The IPS image dwelling in the installation directory. */ private static ExtendedImage img = null; /** * @return True if there's an image in the installation directory, false * it's still to be created. */ public static boolean hasImage () { return img != null; } /** * The frame hosting the installation progress handler. */ private final InstallerFrame frame; /** * True when only trivial operations where performed, false otherwise. A * trivial operation isn't that important; therefore it doesn't require the * user to press the "next" button. */ private boolean trivial = true; /** * @param data The installation data. * @param handler The installation progress handler. * @param parent The frame hosting the installation progress handler. */ public IPSUnpacker (AutomatedInstallData data, AbstractUIProgressHandler handler, InstallerFrame parent) { super(data, handler); frame = parent; } /** * Actually install the IPS packs. * * @see UnpackerBase#run() */ @Override public void run () { handler.startAction("IPSUnpacker", idata.selectedIPSPacks.size() + 3); int job = 0; try { /* * Create and prepare a new IPS image in the installation directory. */ handler.nextStep(idata.langpack.getString("beginning"), ++job, 1); handler.progress(0, idata.langpack.getString("emptyimage")); loadImage(); img.setProxy(idata.proxy); /* * Remove installed packages not marked as installed. */ handler.nextStep(idata.langpack.getString("update"), ++job, 2); if (!idata.unwantedIPSPackages.isEmpty()) { trivial = false; img.uninstallPackages(idata.unwantedIPSPackages); } /* * Upgrade installed packages marked as upgradable. */ ImagePlan plan = img.makeInstallPlan(idata.selectedIPSPackages); if (plan.getProposedFmris().length > 0) { trivial = false; } plan.execute(new ImagePlanProgressTrackerForIzPack(handler, idata.langpack, 1)); /* * Install each IPS pack. */ for (IPSPack pack: idata.selectedIPSPacks) { trivial = false; handler.nextStep(pack.getName(), ++job, 4); installPack(pack); } idata.selectedIPSPacks.clear(); /* * Install the Sun Update Center if the user wants it to be done. */ if (idata.installUpdateCenter) { handler.nextStep( idata.langpack.getString("IPSInstallPanel.updatecenterinstall"), ++job, 1); installUpdateCenter(); } /* * Get the current state of the image. */ loadImage(); idata.installedIPSPackages.clear(); for (FmriState pkg: img.getInventory(null, true)) { if (pkg.installed) { idata.installedIPSPackages.add(pkg); } } } catch (Exception e) { e.printStackTrace(); handler.emitError(e.getClass().getSimpleName(), e.toString()); } finally { handler.stopAction(); } /* * Skip to the next panel if no non trivial operations is performed. */ if (trivial) { frame.skipPanel(); } } /** * Install an IPS pack in the local IPS image. * * @param pack The IPS pack we're to install. */ private void installPack (IPSPack pack) { int step = 0; try { /* * Update an existing authority or add an additional authority for * packages retrieving. */ handler.progress( ++step, idata.langpack.getString("IPSInstallPanel.retrievingcatalog")); img.addAuthority(pack.getAuthority()); /* * Install the packages this pack requires. */ handler.progress( ++step, idata.langpack.getString("IPSInstallPanel.resolvingdependencies")); img.makeInstallPlan(pack.getPackages(img.getInventory())).execute( new ImagePlanProgressTrackerForIzPack(handler, idata.langpack, step)); } catch (Exception e) { e.printStackTrace(); handler.emitWarning(e.getClass().getSimpleName(), e.getLocalizedMessage()); } } /** * Install the Sun Update Center in the local IPS image. * * @throws InterruptedException When the Update Center failed. * @throws IOException When we didn't even manage to launch the Update * Center. */ private void installUpdateCenter () throws InterruptedException, IOException { /* * Create the bootstrap configuration file. */ Properties p = new Properties(); p.setProperty("image.path", idata.getInstallPath()); p.setProperty("install.pkg", "true"); p.setProperty("install.updatetool", "true"); switch (idata.proxy.type()) { case HTTP: p.setProperty("proxy.URL", idata.proxy.address().toString()); break; case SOCKS: /* * TODO What should we do in this case? */ break; } String configFile = idata.getInstallPath() + "/pkg/lib/bootstrap.properties"; File dir = new File(idata.getInstallPath() + "/pkg/lib"); dir.mkdirs(); p.store( new PrintWriter(new BufferedWriter(new FileWriter(configFile))), "Parameters for the UC Bootstrap"); /* * Prepare the command line. */ String[] args = { "java", "-jar", idata.getInstallPath() + "/pkg/lib/pkg-bootstrap.jar", configFile }; /* * Launch the bootstrap. The path "/pkg/lib" is there to allow * `pkg-bootstrap.jar` to find `pkg-client.jar`, which is required. */ Process bootstrap = Runtime.getRuntime().exec(args, null, dir); /* * If the command went fine, launch the Sun Update Center. */ if (bootstrap.waitFor() == 0) { // TODO: there is a problem when the install path contains a space Runtime.getRuntime().exec(idata.getInstallPath().replaceAll(" ", "\\ ") + "/updatetool/bin/updatetool") ; } else { handler.emitNotification(idata.langpack.getString("IPSInstallPanel.updatecentererror")); } } /** * Read the IPS image dwelling in the installation directory. Create a new * image if there's none available. * <p> * Please note that this method can't override an existing image with a * fancy IPS not-so-empty image. * </p> * * @throws Exception When the image can't be created for some reason. */ private void loadImage () throws Exception { File dir = new File(idata.getInstallPath()); try { img = new ExtendedImage(dir); } catch (Exception e) { img = ExtendedImage.create(dir, new ZipInputStream( UnpackerBase.class.getResourceAsStream("/res/" + TEMPLATE))); } } }