/* ******************************************************************* * Copyright (c) 2000-2001 Xerox Corporation, * 2002 Palo Alto Research Center, Incorporated (PARC). * All rights reserved. * This program and the accompanying materials are made available * under the terms of the Eclipse Public License v 2.0 * which accompanies this distribution and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt * * Contributors: * Xerox/PARC initial implementation * ******************************************************************/ package $installer$.org.aspectj; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.net.JarURLConnection; import java.net.URL; import java.util.Enumeration; import java.util.Map; import java.util.Properties; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.border.Border; import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; /** * Invoke the Installer gui. There are two ways to run without GUI by passing parameters to main: *
    *
  1. pass -text {pathToPropertiesFile}: * *
  2. *
  3. pass -to {pathToTargetDir}: * *
  4. */ public class Main { public static void main(String[] args) { Options.loadArgs(args); boolean hasGui = true; Properties properties = new Properties(); InputStream istream = null; try { istream = Main.class.getResourceAsStream(Installer.RESOURCE_DIR + "/properties.txt"); if (istream == null) { System.err.println("unable to load properties.txt using Main.class - exiting"); Main.exit(-1); } properties.load(istream); // when running outside GUI, load values into properties // so that property-value resolution works // (otherwise, could just set values below). // XXX not sure if this indirection is actually needed. if (null != Options.textProperties) { istream.close(); istream = new FileInputStream(Options.textProperties); properties.load(istream); hasGui = false; } else if (null != Options.targetDir) { String path = null; try { path = Options.targetDir.getCanonicalPath(); } catch (IOException e) { path = Options.targetDir.getAbsolutePath(); } String javaPath = ConfigureLauncherPane.getDefaultJavaHomeLocation(); if (null == javaPath) { System.err.println("using GUI - unable to find java"); } else { properties.setProperty("output.dir", path); properties.setProperty("context.javaPath", javaPath); hasGui = false; } } } catch (IOException ioe) { handleException(ioe); } finally { if (null != istream) { try { istream.close(); } catch (IOException e) { } // ignore } } try { String className = (String) properties.get("installer.main.class"); //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); Installer installer = (Installer) Class.forName(className).getDeclaredConstructor().newInstance(); InstallContext installerContext = new InstallContext(properties); installerContext.setHasGui(hasGui); installer.setContext(installerContext); if (installerContext.hasGui()) { // let context force whether or not to run gui installer.runGUI(); } else { // set output dir and java path in context after minimal validation String propName = "output.dir"; String propValue = properties.getProperty(propName); if (null == propValue) { throw new Exception("expecting property " + propName); } String outputDirName = propValue; propName = "context.javaPath"; propValue = properties.getProperty(propName); if (null == propValue) { throw new Exception("expecting property " + propName); } String javaPath = propValue; File outputDir = new File(outputDirName); if (!outputDir.isDirectory()) { throw new Exception("not a dir outputDirName: " + outputDirName + " dir: " + outputDir); } if (!outputDir.canWrite()) { throw new Exception("cannot write outputDirName: " + outputDirName + " dir: " + outputDir); } InstallContext context = installer.getContext(); // todo: why not use installerContext? context.setOutputDir(outputDir); context.javaPath = new File(javaPath); // todo: check javaPath for ... bin/java? lib/rt.jar? if (!outputDir.isDirectory() || !outputDir.canRead()) { throw new Exception("invalid javaPath: " + javaPath); } // directly set context and run WizardPane.setContext(installerContext); installer.run(); } } catch (Exception e) { handleException(e); } } public static void handleException(Throwable e) { System.out.println("internal error: " + e.toString()); e.printStackTrace(); Main.exit(-1); } /** indirection for System.exit - todo apply cleanup here as necessary */ public static void exit(int value) { System.exit(value); } } // class Main class Options { public static boolean verbose = false; public static String textProperties = null; public static File targetDir = null; public static boolean forceError1 = false; public static boolean forceError2 = false; public static boolean forceHandConfigure = false; public static void loadArgs(String[] args) { if (args == null) { return; } for (int i = 0; i < args.length; i++) { String arg = args[i]; if (arg == null) { continue; } if (arg.equals("-verbose")) { verbose = true; } else if (arg.equals("-forceError1")) { forceError1 = true; } else if (arg.equals("-forceError2")) { forceError2 = true; } else if (arg.equals("-forceHandConfigure")) { forceHandConfigure = true; } else if (arg.equals("-text")) { if (i + 1 < args.length) { textProperties = args[++i]; } } else if (arg.equals("-to")) { String next = "no argument"; if (i + 1 < args.length) { next = args[++i]; File targDir = new File(next); if (targDir.isDirectory() && targDir.canWrite()) { targetDir = targDir; } } if (null == targetDir) { System.err.println("invalid -to dir: " + next); } } } } } /** tools installer installs the entire 1.1+ distribution */ class ToolsInstaller extends Installer { public String getTitle() { return "Installer for AspectJ(TM)"; } public String getPrefix() { return "tools"; } public String getReadmeFilename() { return "README-AspectJ.html"; } public ToolsInstaller() { InstallPane installPane = new InstallPane(true); setInstallPane(installPane); panes = new WizardPane[] { new IntroPane(), new ConfigureLauncherPane(), new LocationPane(), installPane, new FinishPane() }; } } class DocsInstaller extends Installer { public String getTitle() { return "AspectJ(TM) Documentation and Examples Installer"; } public String getPrefix() { return "docs"; } public DocsInstaller() { InstallPane installPane = new InstallPane(false); setInstallPane(installPane); panes = new WizardPane[] { new IntroPane(), new LocationPane(), installPane, new FinishPane() }; } } class AJDEForJBuilderInstaller extends Installer { public String getTitle() { return "AspectJ(TM) Support for JBuilder"; } public String getPrefix() { return "ajdeForJBuilder"; } public AJDEForJBuilderInstaller() { InstallPane installPane = new InstallPane(false); setInstallPane(installPane); panes = new WizardPane[] { new IntroPane(), new LocationPane() { public String getDefaultLocation() { if (context.onWindows()) { // check some default locations String[] paths = { "c:\\JBuilder6\\lib\\ext", "c:\\apps\\JBuilder6\\lib\\ext", "c:\\Program Files\\JBuilder6\\lib\\ext" }; int pathIndex = 0; for (; pathIndex < paths.length; pathIndex++) { if (new File(paths[pathIndex]).exists()) { return paths[pathIndex]; } } return "c:\\JBuilder6\\lib\\ext"; } else { return "/usr/JBuilder6/lib/ext"; } } /** * Make sure that the old jar file gets removed. */ public void verify() { File jbuilder = new File(location.getText() + "/../../lib/jbuilder.jar"); if (!jbuilder.exists() && hasGui()) { int ret = JOptionPane.showConfirmDialog(frame, "The location you specified does not seem to be a " + "valid JBuilder install directory." + " Continue?", "Confirm Install", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (ret != JOptionPane.YES_OPTION) { Main.exit(-1); } else { // do nothing } } File oldFile = new File(location.getText() + "/ajbuilder.jar"); if (oldFile.exists() && hasGui()) { int ret = JOptionPane.showConfirmDialog(frame, "This old version of AJDE for JBuilder (\"ajbuilder.jar\") exists" + " and must be removed from the install directory." + " OK to delete?", "Confirm Delete", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (ret != JOptionPane.YES_OPTION) { Main.exit(-1); } else { oldFile.delete(); } } } }, installPane, new FinishPane() }; } } class AJDEForForteInstaller extends Installer { public String getTitle() { return "AspectJ(TM) Support for Forte 4J"; } public String getPrefix() { return "ajdeForForte"; } private String installLoc = ""; public AJDEForForteInstaller() { InstallPane installPane = new InstallPane(false); setInstallPane(installPane); panes = new WizardPane[] { new IntroPane(), new LocationPane() { public String getDefaultLocation() { if (context.onWindows()) { // check some default locations String[] paths = { "c:\\forte4j\\modules", "c:\\apps\\forte4j\\modules", "c:\\Program Files\\forte4j\\modules" }; int pathIndex = 0; for (; pathIndex < paths.length; pathIndex++) { if (new File(paths[pathIndex]).exists()) { return paths[pathIndex]; } } return "c:\\forte4j\\modules"; } else { return "/usr/forte4j/modules"; } } public void verify() { File forte = new File(location.getText() + "/../lib/openide.jar"); installLoc = location.getText(); if (!forte.exists() && hasGui()) { int ret = JOptionPane.showConfirmDialog(frame, "The location you specified does not seem to be a " + "valid Forte install directory." + " Continue?", "Confirm Install", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (ret != JOptionPane.YES_OPTION) { Main.exit(-1); } else { // do nothing } } } }, installPane, new FinishPane() { public void finalActions() { // todo verify dir ../lib/ext exists? // !!! this should be done with two install locations, not by moving a file new File(installLoc + "/../lib/ext/aspectjrt.jar").delete(); new File(installLoc + "/aspectjrt.jar").renameTo(new File((installLoc + "/../lib/ext/aspectjrt.jar"))); new File(installLoc + "/aspectjrt.jar").delete(); } } }; } } class SrcInstaller extends Installer { public String getTitle() { return "AspectJ(TM) Compiler and Core Tools Sources Installer"; } public String getPrefix() { return "sources"; } public SrcInstaller() { InstallPane installPane = new InstallPane(false); setInstallPane(installPane); panes = new WizardPane[] { new IntroPane(), new LocationPane(), installPane, new FinishPane() }; } } abstract class Installer { static final String EXIT_MESSAGE = "Are you sure you want to cancel the installation?"; static final String EXIT_TITLE = "Exiting installer"; /** * relative directory in jar from package $installer$.org.aspectj for loading resources - todo must be tracked during build */ public static final String RESOURCE_DIR = "resources"; JFrame frame; InstallContext context; /** special pane that actually does the installation */ InstallPane installPane; public Installer() { } protected void setInstallPane(InstallPane installPane) { this.installPane = installPane; } public InstallPane getInstallPane() { return installPane; } /** directly run the install pane, if any */ public void run() { if (null != installPane) { installPane.run(); } } public abstract String getPrefix(); public String getReadmeFilename() { return "README-" + getPrefix().toUpperCase() + ".html"; } public void setContext(InstallContext context) { this.context = context; context.installer = this; } public InstallContext getContext() { return context; } public String getTitle() { return "AspectJ(TM) Installer"; } public int getWidth() { return 640; } public int getHeight() { return 460; } protected WizardPane[] panes = new WizardPane[0]; public WizardPane[] getPanes() { return panes; } public int findPaneIndex(WizardPane pane) { for (int i = 0; i < panes.length; i++) { if (panes[i] == pane) { return i; } } return -1; } Component header, footer, body; public void runGUI() { frame = new JFrame(getTitle()); WindowListener wl = new WindowAdapter() { public void windowClosing(WindowEvent arg0) { Main.exit(-1); // -1 unless exiting through done button } }; frame.addWindowListener(wl); if (Options.forceError1) { throw new RuntimeException("forced error1 for testing purposes"); } Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); int x = (int) (size.getWidth() - getWidth()) / 2; int y = (int) (size.getHeight() - getHeight()) / 2; //include a few sanity checks on starting position if (x < 0) { x = 0; } if (x > 600) { x = 600; } if (y < 0) { y = 0; } if (y > 400) { y = 400; } frame.setLocation(x, y); frame.setSize(getWidth(), getHeight()); moveToPane(getPanes()[0]); frame.setVisible(true); } public void moveToPane(WizardPane pane) { WizardPane.setContext(this.context); Dimension size = frame.getContentPane().getSize(); JPanel contents = new JPanel(); contents.setLayout(new BorderLayout()); header = makeHeader(); contents.add(header, BorderLayout.NORTH); body = pane.getPanel(); contents.add(body, BorderLayout.CENTER); footer = pane.getButtons(); contents.add(footer, BorderLayout.SOUTH); contents.revalidate(); contents.setSize(size); frame.setContentPane(contents); //XXX deal with threading here? pane.run(); } public Icon loadImage(String name) { return new javax.swing.ImageIcon(this.getClass().getResource(name)); } public Component makeHeader() { return new JLabel(loadImage(Installer.RESOURCE_DIR + "/aspectjBanner.gif")); } public ActionListener makeNextAction(final WizardPane pane) { int nextPaneIndex = findPaneIndex(pane) + 1; if (nextPaneIndex >= getPanes().length) { return null; } final WizardPane nextPane = getPanes()[nextPaneIndex]; return new ActionListener() { public void actionPerformed(ActionEvent e) { pane.finish(); moveToPane(nextPane); } }; } public ActionListener makeBackAction(final WizardPane pane) { int nextPaneIndex = findPaneIndex(pane) - 1; if (nextPaneIndex < 0) { return null; } final WizardPane nextPane = getPanes()[nextPaneIndex]; return new ActionListener() { public void actionPerformed(ActionEvent e) { moveToPane(nextPane); } }; } public ActionListener makeCancelAction(WizardPane pane) { return new ActionListener() { public void actionPerformed(ActionEvent e) { int ret = JOptionPane.showConfirmDialog(frame, EXIT_MESSAGE, EXIT_TITLE, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (ret == JOptionPane.YES_OPTION) { Main.exit(-1); } } }; } public ActionListener makeFinishAction(WizardPane pane) { return new ActionListener() { public void actionPerformed(ActionEvent e) { Main.exit(0); } }; } } // willing to go up to 3 levels deep to find either jre or jdk // jre\[*\]lib\ext // jdk*\lib\tools.jar /***** * final static int MAX_DEPTH = 4; public static void findPaths(String prefix, File currentDir, int currentDepth) { if (currentDepth * > MAX_DEPTH) return; if (!currentDir.exists() || !currentDir.isDirectory()) return; File [] files = currentDir.listFiles(); if * (files == null) return; for (int i=0; i properties; public boolean hasGui() { return hasGui; } public void setHasGui(boolean hasGui) { if (this.hasGui != hasGui) { this.hasGui = hasGui; } } public Font getFont() { return new Font("Serif", Font.PLAIN, 14); } public String getOS() { return System.getProperty("os.name"); } public boolean onOS2() { return getOS().equals("OS2") || getOS().equals("OS/2"); } public boolean onWindows() { return getOS().startsWith("Windows") || onOS2(); } public boolean onWindowsPro() { // TODO: Think about a more future-proof solution also checking 'os.version' system property. See also this table: // https://github.com/openjdk/jdk/blob/9604ee82690f89320614b37bfef4178abc869777/src/java.base/windows/native/libjava/java_props_md.c#L446 // Alternatively, explicitly exclude unsupported versions because those won't change in the future. return getOS().matches("^Windows (NT|2000|XP|Vista|Server|7|8|10).*"); } public boolean onMacintosh() { return getOS().startsWith("Mac"); } public boolean onUnix() { return !onWindows(); } static final String[] TEXT_EXTENSIONS = { ".txt", ".text", ".htm", ".html", ".java", ".ajava", "README", ".lst" }; public boolean isTextFile(File file) { String name = file.getName(); for (String textExtension : TEXT_EXTENSIONS) { if (name.endsWith(textExtension)) { return true; } } return false; } public void handleException(Throwable e) { System.out.println("internal error: " + e.toString()); e.printStackTrace(); if (hasGui()) { JOptionPane.showMessageDialog(installer.frame, e.toString(), "Unexpected Exception", JOptionPane.ERROR_MESSAGE); } } final static String OVERWRITE_MESSAGE = "Overwrite file "; final static String OVERWRITE_TITLE = "Overwrite?"; final static String[] OVERWRITE_OPTIONS = { "Yes", "No", "Yes to all" //, "No to all" }; final static int OVERWRITE_YES = 0; final static int OVERWRITE_NO = 1; final static int OVERWRITE_ALL = 2; //final static int OVERWRITE_NONE = 3; int overwriteState = OVERWRITE_NO; boolean shouldOverwrite(final File file) { //System.out.println("overwrite: " + file + " state " + overwriteState); if (overwriteState == OVERWRITE_ALL) { return true; //if (overwriteState == OVERWRITE_NONE) return false; } try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { int ret = JOptionPane.showOptionDialog(installer.frame, OVERWRITE_MESSAGE + file.getPath(), OVERWRITE_TITLE, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, OVERWRITE_OPTIONS, OVERWRITE_OPTIONS[OVERWRITE_YES]); overwriteState = ret; } }); } catch (InvocationTargetException ite) { handleException(ite.getTargetException()); } catch (InterruptedException ie) { } return overwriteState == OVERWRITE_YES || overwriteState == OVERWRITE_ALL; } public Map getProperties() { return properties; } } abstract class WizardPane { static InstallContext context; protected JButton backButton = null; protected JButton nextButton = null; protected JButton cancelButton = null; public static void setContext(InstallContext con) { context = con; } public abstract JPanel makePanel(); protected JTextArea makeTextArea(String data) { JTextArea text = new JTextArea(data); text.setOpaque(false); text.setFont(context.getFont()); text.setEditable(false); return text; } /** @return false only if there is an InstallContext saying there is no GUI */ protected boolean hasGui() { final InstallContext icontext = context; return ((null == icontext) || icontext.hasGui()); } public static String stringFromStream(InputStream stream) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "US-ASCII")); StringBuilder ret = new StringBuilder(); int data; while ((data = reader.read()) != -1) { ret.append((char) data); } return ret.toString(); } public static String removeHead(String text) { int startIndex = text.indexOf(""); int stopIndex = text.indexOf(""); if (startIndex == -1 || stopIndex == -1) { return text; } stopIndex += 7; return text.substring(0, startIndex) + text.substring(stopIndex); } static String styleHeader = "";/* *