[izpack-changes] r1879 - in izpack-src/trunk/src/lib/com/izforge/izpack: . compiler installer
noreply at berlios.de
noreply at berlios.de
Mon Oct 8 00:21:38 CEST 2007
Author: vralev
Date: 2007-10-08 00:21:30 +0200 (Mon, 08 Oct 2007)
New Revision: 1879
Added:
izpack-src/trunk/src/lib/com/izforge/izpack/installer/DownloadPanel.java
izpack-src/trunk/src/lib/com/izforge/izpack/installer/LoggedInputStream.java
izpack-src/trunk/src/lib/com/izforge/izpack/installer/WebRepositoryAccessor.java
Modified:
izpack-src/trunk/src/lib/com/izforge/izpack/PackFile.java
izpack-src/trunk/src/lib/com/izforge/izpack/compiler/MultiVolumePackager.java
izpack-src/trunk/src/lib/com/izforge/izpack/compiler/PackInfo.java
izpack-src/trunk/src/lib/com/izforge/izpack/compiler/Packager.java
izpack-src/trunk/src/lib/com/izforge/izpack/installer/Unpacker.java
izpack-src/trunk/src/lib/com/izforge/izpack/installer/WebAccessor.java
Log:
Big Web Installer Update
Modified: izpack-src/trunk/src/lib/com/izforge/izpack/PackFile.java
===================================================================
--- izpack-src/trunk/src/lib/com/izforge/izpack/PackFile.java 2007-10-07 22:12:26 UTC (rev 1878)
+++ izpack-src/trunk/src/lib/com/izforge/izpack/PackFile.java 2007-10-07 22:21:30 UTC (rev 1879)
@@ -99,7 +99,7 @@
/** Additional attributes or any else for customisation */
private Map additionals = null;
- public int previousPackNumber = -1;
+ public String previousPackId = null;
public long offsetInPreviousPack = -1;
@@ -193,10 +193,10 @@
return null;
}
- public void setPreviousPackFileRef(int previousPackNumber, long offsetInPreviousPack)
+ public void setPreviousPackFileRef(String previousPackId, Long offsetInPreviousPack)
{
- this.previousPackNumber = previousPackNumber;
- this.offsetInPreviousPack = offsetInPreviousPack;
+ this.previousPackId = previousPackId;
+ this.offsetInPreviousPack = offsetInPreviousPack.longValue();
}
/** The target operating system constraints of this file */
@@ -230,7 +230,7 @@
public final boolean isBackReference()
{
- return (previousPackNumber >= 0);
+ return (previousPackId != null);
}
/** The full path name of the target file, using '/' as fileseparator. */
Modified: izpack-src/trunk/src/lib/com/izforge/izpack/compiler/MultiVolumePackager.java
===================================================================
--- izpack-src/trunk/src/lib/com/izforge/izpack/compiler/MultiVolumePackager.java 2007-10-07 22:12:26 UTC (rev 1878)
+++ izpack-src/trunk/src/lib/com/izforge/izpack/compiler/MultiVolumePackager.java 2007-10-07 22:21:30 UTC (rev 1879)
@@ -392,11 +392,11 @@
Debug.trace("Next file: " + file.getAbsolutePath());
// use a back reference if file was in previous pack, and in
// same jar
- long[] info = (long[]) storedFiles.get(file);
+ Object[] info = (Object[]) storedFiles.get(file);
if (info != null && !packJarsSeparate)
{
Debug.trace("File already included in other pack");
- pf.setPreviousPackFileRef((int) info[0], info[1]);
+ pf.setPreviousPackFileRef((String) info[0], (Long)info[1]);
addFile = false;
}
Modified: izpack-src/trunk/src/lib/com/izforge/izpack/compiler/PackInfo.java
===================================================================
--- izpack-src/trunk/src/lib/com/izforge/izpack/compiler/PackInfo.java 2007-10-07 22:12:26 UTC (rev 1878)
+++ izpack-src/trunk/src/lib/com/izforge/izpack/compiler/PackInfo.java 2007-10-07 22:21:30 UTC (rev 1879)
@@ -79,7 +79,7 @@
* @param loose files of pack should be stored separatly or not
* @param excludegroup name of the exclude group
*/
- protected PackInfo(String name, String id, String description, boolean required, boolean loose, String excludegroup)
+ public PackInfo(String name, String id, String description, boolean required, boolean loose, String excludegroup)
{
boolean ispreselected = (excludegroup == null) ? true : false;
pack = new Pack(name, id, description, null, null, required, ispreselected, loose, excludegroup);
Modified: izpack-src/trunk/src/lib/com/izforge/izpack/compiler/Packager.java
===================================================================
--- izpack-src/trunk/src/lib/com/izforge/izpack/compiler/Packager.java 2007-10-07 22:12:26 UTC (rev 1878)
+++ izpack-src/trunk/src/lib/com/izforge/izpack/compiler/Packager.java 2007-10-07 22:21:30 UTC (rev 1879)
@@ -22,6 +22,7 @@
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
@@ -38,6 +39,7 @@
import java.util.zip.ZipInputStream;
import net.n3.nanoxml.XMLElement;
+import net.n3.nanoxml.XMLWriter;
import com.izforge.izpack.Pack;
import com.izforge.izpack.PackFile;
@@ -227,6 +229,9 @@
int packNumber = 0;
Iterator packIter = packsList.iterator();
+
+ XMLElement root = new XMLElement("packs");
+
while (packIter.hasNext())
{
PackInfo packInfo = (PackInfo) packIter.next();
@@ -238,7 +243,7 @@
if (packJarsSeparate)
{
// See installer.Unpacker#getPackAsStream for the counterpart
- String name = baseFile.getName() + ".pack" + packNumber + ".jar";
+ String name = baseFile.getName() + ".pack-" + pack.id + ".jar";
packStream = getJarOutputStream(name);
}
OutputStream comprStream = packStream;
@@ -247,7 +252,7 @@
// Retrieve the correct output stream
org.apache.tools.zip.ZipEntry entry =
- new org.apache.tools.zip.ZipEntry("packs/pack" + packNumber);
+ new org.apache.tools.zip.ZipEntry("packs/pack-" + pack.id);
if( ! compressor.useStandardCompression())
{
entry.setMethod(ZipEntry.STORED);
@@ -282,10 +287,10 @@
// use a back reference if file was in previous pack, and in
// same jar
- long[] lInfo = (long[]) storedFiles.get(file);
- if (lInfo != null && !packJarsSeparate)
+ Object[] info = (Object[]) storedFiles.get(file);
+ if (info != null && !packJarsSeparate)
{
- pf.setPreviousPackFileRef((int) lInfo[0], lInfo[1]);
+ pf.setPreviousPackFileRef((String) info[0], (Long)info[1]);
addFile = false;
}
@@ -303,7 +308,7 @@
throw new IOException("File size mismatch when reading " + file);
inStream.close();
- storedFiles.put(file, new long[] { packNumber, pos});
+ storedFiles.put(file, new Object[] { pack.id, new Long(pos)});
}
// even if not written, it counts towards pack size
@@ -340,9 +345,21 @@
// close pack specific jar if required
if (packJarsSeparate) packStream.closeAlways();
+ XMLElement child = new XMLElement("pack");
+ child.setAttribute("nbytes", new Long(pack.nbytes).toString());
+ child.setAttribute("name", pack.name);
+ if(pack.id != null) child.setAttribute("id", pack.id);
+ root.addChild(child);
+
packNumber++;
}
-
+
+ // Wrtie packsinfo for web installers
+ FileWriter writer = new FileWriter(baseFile.getParent()
+ + File.separator + "packsinfo.xml");
+ XMLWriter xmlwriter = new XMLWriter(writer);
+ xmlwriter.write(root);
+
// Now that we know sizes, write pack metadata to primary jar.
primaryJarStream.putNextEntry(new org.apache.tools.zip.ZipEntry("packs.info"));
ObjectOutputStream out = new ObjectOutputStream(primaryJarStream);
Added: izpack-src/trunk/src/lib/com/izforge/izpack/installer/DownloadPanel.java
===================================================================
--- izpack-src/trunk/src/lib/com/izforge/izpack/installer/DownloadPanel.java 2007-10-07 22:12:26 UTC (rev 1878)
+++ izpack-src/trunk/src/lib/com/izforge/izpack/installer/DownloadPanel.java 2007-10-07 22:21:30 UTC (rev 1879)
@@ -0,0 +1,120 @@
+package com.izforge.izpack.installer;
+
+import javax.swing.*;
+
+import java.awt.event.*;
+import java.awt.*;
+import java.awt.image.*;
+
+/**
+ * Displays progress and stats while downloading repository files.
+ *
+ * @author <a href="vralev at redhat.com">Vladimir Ralev</a>
+ * @version $Revision: 1.1 $
+ */
+public class DownloadPanel extends JDialog implements ActionListener
+{
+ JLabel statusLabel = new JLabel("", JLabel.RIGHT);
+
+ JLabel fileLabel = new JLabel("File", JLabel.LEFT);
+
+ JButton button = new JButton("Cancel");
+
+ JProgressBar progressBar = new JProgressBar();
+
+ String statusText;
+
+ String fileText;
+
+ LoggedInputStream lis;
+
+ public DownloadPanel(LoggedInputStream lis)
+ {
+ Dimension dialogSize = new Dimension(406, 150);
+ this.setLayout(null);
+ this.setMinimumSize(dialogSize);
+ this.setMaximumSize(dialogSize);
+ this.setPreferredSize(dialogSize);
+ this.setAlwaysOnTop(true);
+ this.setResizable(false);
+ this.setSize(dialogSize);
+ this.lis = lis;
+
+ progressBar = new JProgressBar();
+ progressBar.setIndeterminate(false);
+ JPanel contents = (JPanel) getContentPane();
+ contents.setLayout(null);
+ contents.setSize(dialogSize);
+
+ setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+
+ contents.add(fileLabel);
+ contents.add(statusLabel);
+ contents.add(progressBar);
+ contents.add(button);
+
+ button.addActionListener(this);
+
+ fileLabel.setBounds(10, 10, 260, 20);
+ statusLabel.setBounds(270, 10, 120, 20);
+ progressBar.setBounds(10, 35, 380, 20);
+ button.setBounds(200 - 50, 70, 100, 25);
+ pack();
+ }
+
+ public void setStatusLabel(String text)
+ {
+ statusText = text;
+ if (!SwingUtilities.isEventDispatchThread())
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ statusLabel.setText(statusText);
+ }
+ });
+
+ }
+
+ public void setFileLabel(String text)
+ {
+ int maxStr = 35;
+ int lastSeparator = text.lastIndexOf("/");
+ text = text.substring(lastSeparator + 1, text.length());
+ int length = text.length();
+
+ if (length > maxStr)
+ fileText = ".." + text.substring(length - maxStr, length);
+ else
+ fileText = text;
+
+ if (!SwingUtilities.isEventDispatchThread())
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ fileLabel.setText(fileText);
+ }
+ });
+
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ lis.setCancelled(true);
+ this.dispose();
+ }
+
+ public void setProgressMax(int total)
+ {
+ progressBar.setIndeterminate(false);
+ progressBar.setStringPainted(true);
+ progressBar.setMaximum(total);
+ progressBar.setMinimum(0);
+ }
+
+ public void setProgressCurrent(int curr)
+ {
+ progressBar.setValue(curr);
+ }
+}
Added: izpack-src/trunk/src/lib/com/izforge/izpack/installer/LoggedInputStream.java
===================================================================
--- izpack-src/trunk/src/lib/com/izforge/izpack/installer/LoggedInputStream.java 2007-10-07 22:12:26 UTC (rev 1878)
+++ izpack-src/trunk/src/lib/com/izforge/izpack/installer/LoggedInputStream.java 2007-10-07 22:21:30 UTC (rev 1879)
@@ -0,0 +1,142 @@
+package com.izforge.izpack.installer;
+
+import java.io.IOException;
+import java.awt.event.*;
+import java.io.InputStream;
+import javax.swing.*;
+import com.izforge.izpack.Pack;
+
+/**
+ *
+ * Wraps an InputStream in order to track how much bytes are being read, and
+ * then updates the progress dialog. When the stream is opened the progress
+ * dialog shows up. When the stream is closed the dialog is disposed. Make sure
+ * you are closing the streams.
+ *
+ * @author <a href="vralev at redhat.com">Vladimir Ralev</a>
+ * @version $Revision: 1.1 $
+ */
+public class LoggedInputStream extends InputStream
+{
+ private long bytesRead = 0;
+ private InputStream is;
+ private DownloadPanel downloader;
+ private WebAccessor webAccessor;
+ private boolean cancelled = false;
+ private long lastTime = -1;
+ private long lastBytes = -1;
+
+ public void setCancelled(boolean cancel)
+ {
+ cancelled = cancel;
+ }
+
+ public LoggedInputStream(InputStream is, WebAccessor webAccessor)
+ {
+ if(is == null) throw new RuntimeException("Unable to connect");
+ this.is = is;
+ this.webAccessor = webAccessor;
+
+ String sizeStr;
+ if(webAccessor.getContentLength()>0)
+ sizeStr = "(" + Pack.toByteUnitsString(webAccessor.getContentLength()) + ")";
+ else
+ sizeStr = "";
+
+ downloader = new DownloadPanel(this);
+ downloader.setTitle("Downloading");
+ downloader.setFileLabel(webAccessor.getUrl() + " " + sizeStr);
+ downloader.setLocationRelativeTo(null);
+ downloader.setVisible(true);
+ if(webAccessor.getContentLength()>0)
+ {
+ downloader.setProgressMax(webAccessor.getContentLength());
+ downloader.setProgressCurrent(0);
+ }
+ }
+
+ public int available() throws IOException
+ {
+ return is.available();
+ }
+
+ public void close() throws IOException
+ {
+ downloader.setVisible(false);
+ downloader.dispose();
+ is.close();
+ }
+
+ public synchronized void mark(int readlimit)
+ {
+ is.mark(readlimit);
+ }
+
+ public boolean markSupported()
+ {
+ return is.markSupported();
+ }
+
+ public synchronized void reset() throws IOException
+ {
+ is.reset();
+ }
+
+ public long skip(long n) throws IOException
+ {
+ return is.skip(n);
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ int bytes = is.read(b, off, len);
+ if(bytes > 0) bytesRead += bytes;
+ update();
+ return bytes;
+ }
+
+ public int read(byte[] b) throws IOException
+ {
+ int bytes = is.read(b);
+ if(bytes > 0) bytesRead += bytes;
+ update();
+ return bytes;
+ }
+
+ public long getBytesRead()
+ {
+ return bytesRead;
+ }
+
+ public int read() throws IOException
+ {
+ int bytes = is.read();
+ if(bytes > 0) bytesRead += 1;
+ update();
+ return bytes;
+ }
+
+ private void update()
+ {
+ if(lastTime > 0)
+ {
+ long currTime = System.currentTimeMillis();
+ long diff = currTime - lastTime;
+ if(diff > 800)
+ {
+ double bps = (double)(bytesRead-lastBytes)/((double)(diff)/1000.);
+ downloader.setStatusLabel(Pack.toByteUnitsString(Math.round(bps)) + "/s");
+ lastTime = currTime;
+ lastBytes = bytesRead;
+ }
+ }
+ else
+ {
+ lastTime = System.currentTimeMillis();
+ lastBytes = bytesRead;
+ }
+ downloader.setProgressCurrent((int)bytesRead);
+ if(cancelled)
+ throw new RuntimeException("Cancelled");
+ }
+}
\ No newline at end of file
Modified: izpack-src/trunk/src/lib/com/izforge/izpack/installer/Unpacker.java
===================================================================
--- izpack-src/trunk/src/lib/com/izforge/izpack/installer/Unpacker.java 2007-10-07 22:12:26 UTC (rev 1878)
+++ izpack-src/trunk/src/lib/com/izforge/izpack/installer/Unpacker.java 2007-10-07 22:21:30 UTC (rev 1879)
@@ -110,6 +110,8 @@
/** The result of the operation. */
private boolean result = true;
+ private static final String tempPath = "$INSTALL_PATH/Uninstaller/IzpackWebTemp";
+
/**
* The constructor.
*
@@ -304,11 +306,12 @@
{
// We get the pack stream
int n = idata.allPacks.indexOf(packs.get(i));
+ Pack p = (Pack) packs.get(i);
// Custom action listener stuff --- beforePack ----
informListeners(customActions, InstallerListener.BEFORE_PACK, packs.get(i),
new Integer(npacks), handler);
- ObjectInputStream objIn = new ObjectInputStream(getPackAsStream(n));
+ ObjectInputStream objIn = new ObjectInputStream(getPackAsStream(p.id));
// We unpack the files
int nfiles = objIn.readInt();
@@ -432,7 +435,7 @@
InputStream pis = objIn;
if (pf.isBackReference())
{
- InputStream is = getPackAsStream(pf.previousPackNumber);
+ InputStream is = getPackAsStream(pf.previousPackId);
pis = new ObjectInputStream(is);
// must wrap for blockdata use by objectstream
// (otherwise strange result)
@@ -628,10 +631,18 @@
catch (Exception err)
{
// TODO: finer grained error handling with useful error messages
- handler.stopAction();
- handler.emitError("An error occured", err.toString());
- err.printStackTrace();
+ handler.stopAction();
+ if("Installation cancelled".equals(err.getMessage()))
+ {
+ handler.emitNotification("Installation cancelled");
+ }
+ else
+ {
+ handler.emitError("An error occured", err.getMessage());
+ err.printStackTrace();
+ }
this.result = false;
+ System.exit(4);
}
finally
{
@@ -984,15 +995,17 @@
* @return The stream or null if it could not be found.
* @exception Exception Description of the Exception
*/
- private InputStream getPackAsStream(int n) throws Exception
+ private InputStream getPackAsStream(String packid) throws Exception
{
InputStream in = null;
String webDirURL = idata.info.getWebDirURL();
+ packid = "-" + packid;
+
if (webDirURL == null) // local
{
- in = Unpacker.class.getResourceAsStream("/packs/pack" + n);
+ in = Unpacker.class.getResourceAsStream("/packs/pack" + packid);
}
else
// web based
@@ -1003,15 +1016,31 @@
// See compiler.Packager#getJarOutputStream for the counterpart
String baseName = idata.info.getInstallerBase();
- String packURL = webDirURL + "/" + baseName + ".pack" + n + ".jar";
- URL url = new URL("jar:" + packURL + "!/packs/pack" + n);
+ String packURL = webDirURL + "/" + baseName + ".pack" + packid + ".jar";
+ String tf = IoHelper.translatePath(Unpacker.tempPath, vs);
+ String tempfile;
+ try
+ {
+ tempfile = WebRepositoryAccessor.getCachedUrl(packURL, tf);
+ udata.addFile(tempfile);
+ }
+ catch(Exception e)
+ {
+ if("Cancelled".equals(e.getMessage()))
+ throw new InstallerException("Installation cancelled", e);
+ else
+ throw new InstallerException("Installation failed", e);
+ }
+ URL url = new URL("jar:" + tempfile + "!/packs/pack" + packid);
+
+ //URL url = new URL("jar:" + packURL + "!/packs/pack" + packid);
// JarURLConnection jarConnection = (JarURLConnection)
// url.openConnection();
// TODO: what happens when using an automated installer?
in = new WebAccessor(null).openInputStream(url);
// TODO: Fails miserably when pack jars are not found, so this is
// temporary
- if (in == null) throw new FileNotFoundException(url.toString());
+ if (in == null) throw new InstallerException(url.toString() + " not available", new FileNotFoundException(url.toString()));
}
if( in != null && idata.info.getPackDecoderClassName() != null )
{
Modified: izpack-src/trunk/src/lib/com/izforge/izpack/installer/WebAccessor.java
===================================================================
--- izpack-src/trunk/src/lib/com/izforge/izpack/installer/WebAccessor.java 2007-10-07 22:12:26 UTC (rev 1878)
+++ izpack-src/trunk/src/lib/com/izforge/izpack/installer/WebAccessor.java 2007-10-07 22:21:30 UTC (rev 1879)
@@ -43,303 +43,326 @@
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.JProgressBar;
+import java.net.*;
/**
* Dialogs for password authentication and firewall specification, when needed, during web
* installation.
*
* @author Chadwick McHenry
+ * @author <a href="vralev at redhat.com">Vladimir Ralev</a>
* @version 1.0
*/
public class WebAccessor
{
- private Thread openerThread = null;
+ private Thread openerThread = null;
- private InputStream iStream = null;
+ private InputStream iStream = null;
- private Exception exception = null;
+ private Exception exception = null;
- private Object soloCancelOption = null;
+ private Object soloCancelOption = null;
- private Component parent = null;
+ private Component parent = null;
- private JDialog dialog = null;
+ private JDialog dialog = null;
- private boolean tryProxy = false;
+ private boolean tryProxy = false;
- private JPanel passwordPanel = null;
+ private JPanel passwordPanel = null;
- private JLabel promptLabel;
+ private JLabel promptLabel;
- private JTextField nameField;
+ private JTextField nameField;
- private JPasswordField passField;
+ private JPasswordField passField;
- private JPanel proxyPanel = null;
+ private JPanel proxyPanel = null;
- private JLabel errorLabel;
+ private JLabel errorLabel;
- private JTextField hostField;
+ private JTextField hostField;
- private JTextField portField;
+ private JTextField portField;
- /**
- * Not yet Implemented: placeholder for headless installs.
- *
- * @throws UnsupportedOperationException
- */
- public WebAccessor()
- {
- // the class should probably be rearranged to do this.
- throw new UnsupportedOperationException();
- }
+ private String url;
- /**
- * Create a WebAccessor that prompts for proxies and passwords using a JDialog.
- *
- * @param parent determines the frame in which the dialog is displayed; if the parentComponent
- * has no Frame, a default Frame is used
- */
- public WebAccessor(Component parent)
- {
- this.parent = parent;
- Locale l = null;
- if (parent != null) parent.getLocale();
- soloCancelOption = UIManager.get("OptionPane.cancelButtonText", l);// TODO:
- // i18n?
- Authenticator.setDefault(new MyDialogAuthenticator());
- }
+ private int contentLength = -1;
- /**
- * Opens a URL connection and returns it's InputStream for the specified URL.
- *
- * @param url the url to open the stream to.
- * @return an input stream ready to read, or null on failure
- */
- public InputStream openInputStream(URL url)
- {
- // TODO: i18n everything
- Object[] options = { soloCancelOption};
-
- JProgressBar progressBar = new JProgressBar(1, 100);
- progressBar.setIndeterminate(true);
- Object[] contents = { "Connecting to the Internet", progressBar };
- JOptionPane pane = new JOptionPane(contents,
- JOptionPane.INFORMATION_MESSAGE,
- JOptionPane.DEFAULT_OPTION, null, options,
- options[0]);
- dialog = pane.createDialog(parent, "Accessing Install Files");
- pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ /**
+ * Not yet Implemented: placeholder for headless installs.
+ *
+ * @throws UnsupportedOperationException
+ */
+ public WebAccessor()
+ {
+ // the class should probably be rearranged to do this.
+ throw new UnsupportedOperationException();
+ }
- Object value = null;
- OPEN_URL: while (true)
- {
- startOpening(url); // this starts a thread that may dismiss the
- // dialog before user
- dialog.setVisible(true);
- value = pane.getValue();
+ /**
+ * Create a WebAccessor that prompts for proxies and passwords using a JDialog.
+ *
+ * @param parent determines the frame in which the dialog is displayed; if the parentComponent
+ * has no Frame, a default Frame is used
+ */
+ public WebAccessor(Component parent)
+ {
+ this.parent = parent;
+ Locale l = null;
+ if (parent != null)
+ parent.getLocale();
+ soloCancelOption = UIManager.get("OptionPane.cancelButtonText", l);// TODO:
+ // i18n?
+ Authenticator.setDefault(new MyDialogAuthenticator());
+ }
- // dialog closed or canceled (by widget)
- if (value == null || value == soloCancelOption)
+ /**
+ * Opens a URL connection and returns it's InputStream for the specified URL.
+ *
+ * @param url the url to open the stream to.
+ * @return an input stream ready to read, or null on failure
+ */
+ public InputStream openInputStream(URL url)
+ {
+ setUrl(url.toExternalForm());
+ OPEN_URL : while (true)
+ {
+ startOpening(url); // this starts a thread
+
+ Thread.yield();
+
+
+ // Wait a bit to see if the stream comes up
+ int retry = 28;
+ while (exception == null && iStream == null && retry > 0)
+ try
{
- try
- {
- openerThread.interrupt();// stop the connection
- }
- catch (Exception e)
- {}
- iStream = null; // even if connection was made just after cancel
- break;
+ Thread.sleep(200);
+ retry--;
}
-
- // dialog closed by thread so either a connection error or success!
- else if (value == JOptionPane.UNINITIALIZED_VALUE)
+ catch (Exception e)
{
- // success!
- if (iStream != null) break;
+ System.out.println("In openInputStream: " + e);
+ }
- // System.err.println(exception);
+ /* Try to find a proxy if that failed */
- // an exception we don't expect setting a proxy to fix
- if (!tryProxy) break;
+ // success!
+ if (iStream != null)
+ break;
- // else (exception != null)
- // show proxy dialog until valid values or cancel
- JPanel panel = getProxyPanel();
- errorLabel.setText("Unable to connect: " + exception.getMessage());
- while (true)
- {
- int result = JOptionPane.showConfirmDialog(parent, panel,
- "Proxy Configuration", JOptionPane.OK_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE);
- if (result != JOptionPane.OK_OPTION) // canceled
- break OPEN_URL;
+ // an exception we don't expect setting a proxy to fix
+ if (!tryProxy)
+ break;
- String host = null;
- String port = null;
+ // else (exception != null)
+ // show proxy dialog until valid values or cancel
+ JPanel panel = getProxyPanel();
+ errorLabel.setText("Unable to connect: " + exception.getMessage());
+ while (true)
+ {
+ int result = JOptionPane.showConfirmDialog(parent, panel, "Proxy Configuration",
+ JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
+ if (result != JOptionPane.OK_OPTION) // canceled
+ break OPEN_URL;
- try
- {
- InetAddress addr = InetAddress.getByName(hostField.getText());
- host = addr.getHostName();
- }
- catch (Exception x)
- {
- errorLabel.setText("Unable to resolve Host");
- Toolkit.getDefaultToolkit().beep();
- }
+ String host = null;
+ String port = null;
- try
- {
- if (host != null) port = Integer.valueOf(portField.getText()).toString();
- }
- catch (NumberFormatException x)
- {
- errorLabel.setText("Invalid Port");
- Toolkit.getDefaultToolkit().beep();
- }
+ try
+ {
+ InetAddress addr = InetAddress.getByName(hostField.getText());
+ host = addr.getHostName();
+ }
+ catch (Exception x)
+ {
+ errorLabel.setText("Unable to resolve Host");
+ Toolkit.getDefaultToolkit().beep();
+ }
- if (host != null && port != null)
- {
- // System.err.println ("Setting http proxy: "+ host
- // +":"+ port);
- System.getProperties().put("proxySet", "true");
- System.getProperties().put("proxyHost", host);
- System.getProperties().put("proxyPort", port);
- break;
- }
- }
+ try
+ {
+ if (host != null)
+ port = Integer.valueOf(portField.getText()).toString();
}
- }
- return iStream;
- }
+ catch (NumberFormatException x)
+ {
+ errorLabel.setText("Invalid Port");
+ Toolkit.getDefaultToolkit().beep();
+ }
- private void startOpening(final URL url)
- {
- openerThread = new Thread() {
+ if (host != null && port != null)
+ {
+ // System.err.println ("Setting http proxy: "+ host
+ // +":"+ port);
+ System.getProperties().put("proxySet", "true");
+ System.getProperties().put("proxyHost", host);
+ System.getProperties().put("proxyPort", port);
+ break;
+ }
+ }
+ }
- public void run()
+ if (iStream == null)
+ openerThread.interrupt();
+
+ return iStream;
+ }
+
+ private void startOpening(final URL url)
+ {
+ final WebAccessor wa = this;
+ openerThread = new Thread()
+ {
+ public void run()
+ {
+ iStream = null;
+ try
{
- iStream = null;
- try
- {
- tryProxy = false;
- URLConnection connection = url.openConnection();
- iStream = connection.getInputStream(); // just to make
- // connection
+ tryProxy = false;
- }
- catch (ConnectException x)
- { // could be an incorrect proxy
- tryProxy = true;
- exception = x;
+ URLConnection connection = url.openConnection();
- }
- catch (Exception x)
- {
- // Exceptions that get here are considered cancels or
- // missing
- // pages, eg 401 if user finally cancels auth
- exception = x;
+ if (connection instanceof HttpURLConnection)
+ {
+ HttpURLConnection htc = (HttpURLConnection) connection;
+ contentLength = htc.getContentLength();
+ }
- }
- finally
- {
- // if dialog is in use, allow it to become visible /before/
- // closing
- // it, else on /fast/ connectinos, it may open later and
- // hang!
- if (dialog != null)
- {
- Thread.yield();
- dialog.setVisible(false);
- }
- }
+ //InputStream iii = echoSocket.getInputStream();
+ InputStream i = connection.getInputStream();
+ iStream = new LoggedInputStream(i, wa); // just to make
+
}
- };
- openerThread.start();
- }
+ catch (ConnectException x)
+ { // could be an incorrect proxy
+ tryProxy = true;
+ exception = x;
- /**
- * Only to be called after an initial error has indicated a connection problem
- */
- private JPanel getProxyPanel()
- {
- if (proxyPanel == null)
- {
- proxyPanel = new JPanel(new BorderLayout(5, 5));
+ }
+ catch (Exception x)
+ {
+ // Exceptions that get here are considered cancels or
+ // missing
+ // pages, eg 401 if user finally cancels auth
+ exception = x;
- errorLabel = new JLabel();
+ }
+ finally
+ {
+ // if dialog is in use, allow it to become visible /before/
+ // closing
+ // it, else on /fast/ connectinos, it may open later and
+ // hang!
+ if (dialog != null)
+ {
+ Thread.yield();
+ dialog.setVisible(false);
+ }
+ }
+ }
+ };
+ openerThread.start();
+ }
- JPanel fields = new JPanel(new GridLayout(2, 2));
- String h = (String) System.getProperties().get("proxyHost");
- String p = (String) System.getProperties().get("proxyPort");
- hostField = new JTextField(h != null ? h : "");
- portField = new JTextField(p != null ? p : "");
- JLabel host = new JLabel("Host: "); // TODO: i18n
- JLabel port = new JLabel("Port: "); // TODO: i18n
- fields.add(host);
- fields.add(hostField);
- fields.add(port);
- fields.add(portField);
+ /**
+ * Only to be called after an initial error has indicated a connection problem
+ */
+ private JPanel getProxyPanel()
+ {
+ if (proxyPanel == null)
+ {
+ proxyPanel = new JPanel(new BorderLayout(5, 5));
- JLabel exampleLabel = new JLabel("e.g. host=\"gatekeeper.example.com\" port=\"80\"");
+ errorLabel = new JLabel();
- proxyPanel.add(errorLabel, BorderLayout.NORTH);
- proxyPanel.add(fields, BorderLayout.CENTER);
- proxyPanel.add(exampleLabel, BorderLayout.SOUTH);
- }
- proxyPanel.validate();
+ JPanel fields = new JPanel(new GridLayout(2, 2));
+ String h = (String) System.getProperties().get("proxyHost");
+ String p = (String) System.getProperties().get("proxyPort");
+ hostField = new JTextField(h != null ? h : "");
+ portField = new JTextField(p != null ? p : "");
+ JLabel host = new JLabel("Host: "); // TODO: i18n
+ JLabel port = new JLabel("Port: "); // TODO: i18n
+ fields.add(host);
+ fields.add(hostField);
+ fields.add(port);
+ fields.add(portField);
- return proxyPanel;
- }
+ JLabel exampleLabel = new JLabel("e.g. host=\"gatekeeper.example.com\" port=\"80\"");
- private JPanel getPasswordPanel()
- {
- if (passwordPanel == null)
- {
- passwordPanel = new JPanel(new BorderLayout(5, 5));
+ proxyPanel.add(errorLabel, BorderLayout.NORTH);
+ proxyPanel.add(fields, BorderLayout.CENTER);
+ proxyPanel.add(exampleLabel, BorderLayout.SOUTH);
+ }
+ proxyPanel.validate();
- promptLabel = new JLabel();
+ return proxyPanel;
+ }
- JPanel fields = new JPanel(new GridLayout(2, 2));
- nameField = new JTextField();
- passField = new JPasswordField();
- JLabel name = new JLabel("Name: "); // TODO: i18n
- JLabel pass = new JLabel("Password: "); // TODO: i18n
- fields.add(name);
- fields.add(nameField);
- fields.add(pass);
- fields.add(passField);
+ private JPanel getPasswordPanel()
+ {
+ if (passwordPanel == null)
+ {
+ passwordPanel = new JPanel(new BorderLayout(5, 5));
- passwordPanel.add(promptLabel, BorderLayout.NORTH);
- passwordPanel.add(fields, BorderLayout.CENTER);
- }
- passField.setText("");
+ promptLabel = new JLabel();
- return passwordPanel;
- }
+ JPanel fields = new JPanel(new GridLayout(2, 2));
+ nameField = new JTextField();
+ passField = new JPasswordField();
+ JLabel name = new JLabel("Name: "); // TODO: i18n
+ JLabel pass = new JLabel("Password: "); // TODO: i18n
+ fields.add(name);
+ fields.add(nameField);
+ fields.add(pass);
+ fields.add(passField);
- /**
- * Authenticates via dialog when needed.
- */
- private class MyDialogAuthenticator extends Authenticator
- {
+ passwordPanel.add(promptLabel, BorderLayout.NORTH);
+ passwordPanel.add(fields, BorderLayout.CENTER);
+ }
+ passField.setText("");
- public PasswordAuthentication getPasswordAuthentication()
- {
- // TODO: i18n
- JPanel p = getPasswordPanel();
- String prompt = getRequestingPrompt();
- InetAddress addr = getRequestingSite();
- if (addr != null) prompt += " (" + addr.getHostName() + ")";
- promptLabel.setText(prompt);
- int result = JOptionPane.showConfirmDialog(parent, p, "Enter Password",
- JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
- if (result != JOptionPane.OK_OPTION) return null;
+ return passwordPanel;
+ }
- return new PasswordAuthentication(nameField.getText(), passField.getPassword());
- }
- }
+ /**
+ * Authenticates via dialog when needed.
+ */
+ private class MyDialogAuthenticator extends Authenticator
+ {
+
+ public PasswordAuthentication getPasswordAuthentication()
+ {
+ // TODO: i18n
+ JPanel p = getPasswordPanel();
+ String prompt = getRequestingPrompt();
+ InetAddress addr = getRequestingSite();
+ if (addr != null)
+ prompt += " (" + addr.getHostName() + ")";
+ promptLabel.setText(prompt);
+ int result = JOptionPane.showConfirmDialog(parent, p, "Enter Password", JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+ if (result != JOptionPane.OK_OPTION)
+ return null;
+
+ return new PasswordAuthentication(nameField.getText(), passField.getPassword());
+ }
+ }
+
+ public String getUrl()
+ {
+ return url;
+ }
+
+ public void setUrl(String url)
+ {
+ this.url = url;
+ }
+
+ public int getContentLength()
+ {
+ return contentLength;
+ }
}
Added: izpack-src/trunk/src/lib/com/izforge/izpack/installer/WebRepositoryAccessor.java
===================================================================
--- izpack-src/trunk/src/lib/com/izforge/izpack/installer/WebRepositoryAccessor.java 2007-10-07 22:12:26 UTC (rev 1878)
+++ izpack-src/trunk/src/lib/com/izforge/izpack/installer/WebRepositoryAccessor.java 2007-10-07 22:21:30 UTC (rev 1879)
@@ -0,0 +1,594 @@
+package com.izforge.izpack.installer;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.*;
+import java.io.*;
+import com.izforge.izpack.compiler.*;
+import com.izforge.izpack.*;
+import com.izforge.izpack.util.*;
+
+import com.izforge.izpack.compiler.CompilerException;
+
+import net.n3.nanoxml.*;
+
+/**
+ *
+ * This class enumerates the availabe packs at the web repository. Parses the config files
+ * - install.xml, packsinfo.xml, langpacks and is used to override the static configuration
+ * in the installer jar.
+ *
+ * @author <a href="vralev at redhat.com">Vladimir Ralev</a>
+ * @version $Revision: 1.1 $
+ */
+public class WebRepositoryAccessor
+{
+ /** URL to remote install.xml */
+ private String installXmlUrl;
+
+ /** Base repository URL */
+ private String baseUrl;
+
+ /** install.xml */
+ private String installXmlString;
+
+ /** packsinfo.xml contains nbytes, pack name and pack id */
+ private String packsInfo;
+
+ /** list of PackInfo entries */
+ private ArrayList packs;
+
+ /** Constant for checking attributes. */
+ private static boolean YES = true;
+
+ /** Constant for checking attributes. */
+ private static boolean NO = false;
+
+ /** Files to be looked for at the repository base url */
+ private static final String installFilename = "install.xml";
+
+ private static final String packsinfoFilename = "packsinfo.xml";
+
+ /** Files being downloaded in the buffer, 1MB max */
+ private static final int BUFFER_SIZE = 1000000;
+
+
+ /**
+ *
+ * Create a new WebRepositoryAccessor.
+ *
+ * @param urlbase
+ */
+ public WebRepositoryAccessor(String urlbase)
+ {
+ this.installXmlUrl = urlbase + "/" + installFilename;
+ this.baseUrl = urlbase;
+ }
+
+ /**
+ * Get the list of the packs from the remore install.xml
+ *
+ * @return
+ */
+ public ArrayList getOnlinePacks()
+ {
+ readConfig();
+ packs = parsePacks();
+ readPacksInfo();
+ parsePacksInfo();
+ return packs;
+ }
+
+ /**
+ * Returns the contents of a file at url as a string (must be a text file)
+ *
+ * @param url
+ * @return
+ */
+ private String stringFromURL(String url)
+ {
+ int max = BUFFER_SIZE;
+ byte[] raw = new byte[max];
+ InputStream in = null;
+ try
+ {
+ WebAccessor w = new WebAccessor(null);
+ in = w.openInputStream(new URL(url));
+ if (in == null)
+ throw new RuntimeException("Unable to open network stream");
+ int r = in.read(raw);
+ int off = r;
+ while (r > 0)
+ {
+ r = in.read(raw, off, max - off);
+ off += r;
+ }
+ return new String(raw);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e + " while trying to download " + url);
+ return null;
+ }
+ finally
+ {
+ try
+ {
+ if(in != null) in.close();
+ }
+ catch(Exception e){}
+ }
+ }
+
+ /**
+ * Reads the install.xml into confgiString
+ *
+ */
+ private void readConfig()
+ {
+ installXmlString = stringFromURL(installXmlUrl);
+ }
+
+
+ /**
+ * Reads packsinfo.xml
+ *
+ */
+ private void readPacksInfo()
+ {
+ String url = this.baseUrl + "/" + packsinfoFilename;
+ packsInfo = stringFromURL(url);
+ }
+
+ /**
+ * Parse install.xml and return the list of packs
+ *
+ * @return
+ */
+ private ArrayList parsePacks()
+ {
+ try
+ {
+ IXMLParser parser = XMLParserFactory.createDefaultXMLParser();
+ IXMLReader reader = StdXMLReader.stringReader(installXmlString);
+ parser.setReader(reader);
+ XMLElement xml = (XMLElement) parser.parse();
+ return loadPacksList(xml);
+ }
+ catch (Exception e)
+ {
+ System.out.println("WARN: Unable to parse install.xml");
+ return null;
+ }
+ }
+
+ /**
+ * Parse packsinfo.xml, fill the nbytes field, which is not available at runtime
+ * otherwise.
+ *
+ */
+ private void parsePacksInfo()
+ {
+ try
+ {
+ IXMLParser parser = XMLParserFactory.createDefaultXMLParser();
+ IXMLReader reader = StdXMLReader.stringReader(packsInfo);
+ parser.setReader(reader);
+ XMLElement xml = (XMLElement) parser.parse();
+ XMLElement root = xml; //requireChildNamed(xml, "packs");
+ for (int q = 0; q < root.getChildrenCount(); q++)
+ {
+ XMLElement ch = root.getChildAtIndex(q);
+ PackInfo pi = (PackInfo) packs.get(q);
+ Pack p = pi.getPack();
+ p.nbytes = Long.parseLong(ch.getAttribute("nbytes"));
+ }
+ }
+ catch (Exception e)
+ {
+ System.out.println("WARN: Unable to parse packsinfo.xml");
+ }
+ }
+
+ /**
+ * First download the jar file. The create the input stream from the
+ * downloaded file. This is because the Jar connection's openInputStream
+ * will blocks until the whole jar in order to unzip it (there is no way
+ * to see the download progress there).
+ *
+ * @param url
+ * @return
+ */
+ public static String getCachedUrl(String url, String tempFolder) throws Exception
+ {
+ int max = BUFFER_SIZE;
+ byte[] raw = new byte[max];
+ try
+ {
+ WebAccessor w = new WebAccessor(null);
+ InputStream in = w.openInputStream(new URL(url));
+ int r = in.read(raw);
+ File tempDir = new File(tempFolder);
+
+ tempDir.mkdirs();
+
+ File temp = File.createTempFile("izpacktempfile", "jar", new File(tempFolder));
+ FileOutputStream fos = new FileOutputStream(temp);
+ String path = "file:///" + temp.getAbsolutePath();
+ while (r > 0)
+ {
+ fos.write(raw, 0, r);
+ r = in.read(raw);
+ }
+ in.close();
+ fos.close();
+
+ return path;
+ }
+ catch (SecurityException e)
+ {
+ System.out.println(e + " while trying to write temp file: " + tempFolder);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ System.out.println(e + " while trying to download " + url);
+ throw e;
+ }
+ }
+
+
+ protected ArrayList loadPacksList(XMLElement data) throws CompilerException
+ {
+ ArrayList result = new ArrayList();
+
+ // Initialisation
+ XMLElement root = requireChildNamed(data, "packs");
+
+ // at least one pack is required
+ Vector packElements = root.getChildrenNamed("pack");
+ if (packElements.isEmpty())
+ parseError(root, "<packs> requires a <pack>");
+
+ Iterator packIter = packElements.iterator();
+ while (packIter.hasNext())
+ {
+ XMLElement el = (XMLElement) packIter.next();
+
+ // Trivial initialisations
+ String name = requireAttribute(el, "name");
+ String id = el.getAttribute("id");
+
+ boolean loose = "true".equalsIgnoreCase(el.getAttribute("loose", "false"));
+ String description = requireChildNamed(el, "description").getContent();
+ boolean required = requireYesNoAttribute(el, "required");
+ String group = el.getAttribute("group");
+ String installGroups = el.getAttribute("installGroups");
+ String excludeGroup = el.getAttribute("excludeGroup");
+ String parent = el.getAttribute("parent");
+
+ if (required && excludeGroup != null)
+ {
+ parseError(el, "Pack, which has excludeGroup can not be required.", new Exception(
+ "Pack, which has excludeGroup can not be required."));
+ }
+
+ PackInfo pack = new PackInfo(name, id, description, required, loose, excludeGroup);
+ pack.setOsConstraints(OsConstraint.getOsList(el)); // TODO:
+ pack.setParent(parent);
+
+ // unverified
+ // if the pack belongs to an excludeGroup it's not preselected by default
+ if (excludeGroup == null)
+ pack.setPreselected(validateYesNoAttribute(el, "preselected", YES));
+ else
+ pack.setPreselected(validateYesNoAttribute(el, "preselected", NO));
+
+ // Set the pack group if specified
+ if (group != null)
+ pack.setGroup(group);
+ // Set the pack install groups if specified
+ if (installGroups != null)
+ {
+ StringTokenizer st = new StringTokenizer(installGroups, ",");
+ while (st.hasMoreTokens())
+ {
+ String igroup = st.nextToken();
+ pack.addInstallGroup(igroup);
+ }
+ }
+
+ // We get the parsables list
+ Iterator iter = el.getChildrenNamed("parsable").iterator();
+ while (iter.hasNext())
+ {
+ XMLElement p = (XMLElement) iter.next();
+ String target = requireAttribute(p, "targetfile");
+ String type = p.getAttribute("type", "plain");
+ String encoding = p.getAttribute("encoding", null);
+ List osList = OsConstraint.getOsList(p); // TODO: unverified
+
+ pack.addParsable(new ParsableFile(target, type, encoding, osList));
+ }
+
+ // We get the executables list
+ iter = el.getChildrenNamed("executable").iterator();
+ while (iter.hasNext())
+ {
+ XMLElement e = (XMLElement) iter.next();
+ ExecutableFile executable = new ExecutableFile();
+ String val; // temp value
+
+ executable.path = requireAttribute(e, "targetfile");
+
+ // when to execute this executable
+ val = e.getAttribute("stage", "never");
+ if ("postinstall".equalsIgnoreCase(val))
+ executable.executionStage = ExecutableFile.POSTINSTALL;
+ else if ("uninstall".equalsIgnoreCase(val))
+ executable.executionStage = ExecutableFile.UNINSTALL;
+
+ // type of this executable
+ val = e.getAttribute("type", "bin");
+ if ("jar".equalsIgnoreCase(val))
+ {
+ executable.type = ExecutableFile.JAR;
+ executable.mainClass = e.getAttribute("class"); // executable
+ // class
+ }
+
+ // what to do if execution fails
+ val = e.getAttribute("failure", "ask");
+ if ("abort".equalsIgnoreCase(val))
+ executable.onFailure = ExecutableFile.ABORT;
+ else if ("warn".equalsIgnoreCase(val))
+ executable.onFailure = ExecutableFile.WARN;
+
+ // whether to keep the executable after executing it
+ val = e.getAttribute("keep");
+ executable.keepFile = "true".equalsIgnoreCase(val);
+
+ // get arguments for this executable
+ XMLElement args = e.getFirstChildNamed("args");
+ if (null != args)
+ {
+ Iterator argIterator = args.getChildrenNamed("arg").iterator();
+ while (argIterator.hasNext())
+ {
+ XMLElement arg = (XMLElement) argIterator.next();
+ executable.argList.add(requireAttribute(arg, "value"));
+ }
+ }
+
+ executable.osList = OsConstraint.getOsList(e); // TODO:
+ // unverified
+
+ pack.addExecutable(executable);
+ }
+
+ // get the updatechecks list
+ iter = el.getChildrenNamed("updatecheck").iterator();
+ while (iter.hasNext())
+ {
+ XMLElement f = (XMLElement) iter.next();
+
+ String casesensitive = f.getAttribute("casesensitive");
+
+ // get includes and excludes
+ ArrayList includesList = new ArrayList();
+ ArrayList excludesList = new ArrayList();
+
+ // get includes and excludes
+ Iterator include_it = f.getChildrenNamed("include").iterator();
+ while (include_it.hasNext())
+ {
+ XMLElement inc_el = (XMLElement) include_it.next();
+ includesList.add(requireAttribute(inc_el, "name"));
+ }
+
+ Iterator exclude_it = f.getChildrenNamed("exclude").iterator();
+ while (exclude_it.hasNext())
+ {
+ XMLElement excl_el = (XMLElement) exclude_it.next();
+ excludesList.add(requireAttribute(excl_el, "name"));
+ }
+
+ pack.addUpdateCheck(new UpdateCheck(includesList, excludesList, casesensitive));
+ }
+ // We get the dependencies
+ iter = el.getChildrenNamed("depends").iterator();
+ while (iter.hasNext())
+ {
+ XMLElement dep = (XMLElement) iter.next();
+ String depName = requireAttribute(dep, "packname");
+ pack.addDependency(depName);
+
+ }
+ result.add(pack);
+ }
+ return result;
+ }
+
+ /**
+ * Create parse error with consistent messages. Includes file name. For use When parent is
+ * unknown.
+ *
+ * @param message Brief message explaining error
+ */
+ protected void parseError(String message) throws CompilerException
+ {
+ throw new CompilerException(installFilename + ":" + message);
+ }
+
+ /**
+ * Create parse error with consistent messages. Includes file name and line # of parent. It is
+ * an error for 'parent' to be null.
+ *
+ * @param parent The element in which the error occured
+ * @param message Brief message explaining error
+ */
+ protected void parseError(XMLElement parent, String message) throws CompilerException
+ {
+ throw new CompilerException(installFilename + ":" + parent.getLineNr() + ": " + message);
+ }
+
+ /**
+ * Create a chained parse error with consistent messages. Includes file name and line # of
+ * parent. It is an error for 'parent' to be null.
+ *
+ * @param parent The element in which the error occured
+ * @param message Brief message explaining error
+ */
+ protected void parseError(XMLElement parent, String message, Throwable cause) throws CompilerException
+ {
+ throw new CompilerException(installFilename + ":" + parent.getLineNr() + ": " + message, cause);
+ }
+
+ /**
+ * Create a parse warning with consistent messages. Includes file name and line # of parent. It
+ * is an error for 'parent' to be null.
+ *
+ * @param parent The element in which the warning occured
+ * @param message Warning message
+ */
+ protected void parseWarn(XMLElement parent, String message)
+ {
+ System.out.println(installFilename + ":" + parent.getLineNr() + ": " + message);
+ }
+
+ /**
+ * Call getFirstChildNamed on the parent, producing a meaningful error message on failure. It is
+ * an error for 'parent' to be null.
+ *
+ * @param parent The element to search for a child
+ * @param name Name of the child element to get
+ */
+ protected XMLElement requireChildNamed(XMLElement parent, String name) throws CompilerException
+ {
+ XMLElement child = parent.getFirstChildNamed(name);
+ if (child == null)
+ parseError(parent, "<" + parent.getName() + "> requires child <" + name + ">");
+ return child;
+ }
+
+ /**
+ * Call getContent on an element, producing a meaningful error message if not present, or empty,
+ * or a valid URL. It is an error for 'element' to be null.
+ *
+ * @param element The element to get content of
+ */
+ protected URL requireURLContent(XMLElement element) throws CompilerException
+ {
+ URL url = null;
+ try
+ {
+ url = new URL(requireContent(element));
+ }
+ catch (MalformedURLException x)
+ {
+ parseError(element, "<" + element.getName() + "> requires valid URL", x);
+ }
+ return url;
+ }
+
+ /**
+ * Call getContent on an element, producing a meaningful error message if not present, or empty.
+ * It is an error for 'element' to be null.
+ *
+ * @param element The element to get content of
+ */
+ protected String requireContent(XMLElement element) throws CompilerException
+ {
+ String content = element.getContent();
+ if (content == null || content.length() == 0)
+ parseError(element, "<" + element.getName() + "> requires content");
+ return content;
+ }
+
+ /**
+ * Call getAttribute on an element, producing a meaningful error message if not present, or
+ * empty. It is an error for 'element' or 'attribute' to be null.
+ *
+ * @param element The element to get the attribute value of
+ * @param attribute The name of the attribute to get
+ */
+ protected String requireAttribute(XMLElement element, String attribute) throws CompilerException
+ {
+ String value = element.getAttribute(attribute);
+ if (value == null)
+ parseError(element, "<" + element.getName() + "> requires attribute '" + attribute + "'");
+ return value;
+ }
+
+ /**
+ * Get a required attribute of an element, ensuring it is an integer. A meaningful error message
+ * is generated as a CompilerException if not present or parseable as an int. It is an error for
+ * 'element' or 'attribute' to be null.
+ *
+ * @param element The element to get the attribute value of
+ * @param attribute The name of the attribute to get
+ */
+ protected int requireIntAttribute(XMLElement element, String attribute) throws CompilerException
+ {
+ String value = element.getAttribute(attribute);
+ if (value == null || value.length() == 0)
+ parseError(element, "<" + element.getName() + "> requires attribute '" + attribute + "'");
+ try
+ {
+ return Integer.parseInt(value);
+ }
+ catch (NumberFormatException x)
+ {
+ parseError(element, "'" + attribute + "' must be an integer");
+ }
+ return 0; // never happens
+ }
+
+ /**
+ * Call getAttribute on an element, producing a meaningful error message if not present, or one
+ * of "yes" or "no". It is an error for 'element' or 'attribute' to be null.
+ *
+ * @param element The element to get the attribute value of
+ * @param attribute The name of the attribute to get
+ */
+ protected boolean requireYesNoAttribute(XMLElement element, String attribute) throws CompilerException
+ {
+ String value = requireAttribute(element, attribute);
+ if ("yes".equalsIgnoreCase(value))
+ return true;
+ if ("no".equalsIgnoreCase(value))
+ return false;
+
+ parseError(element, "<" + element.getName() + "> invalid attribute '" + attribute + "': Expected (yes|no)");
+
+ return false; // never happens
+ }
+
+ /**
+ * Call getAttribute on an element, producing a meaningful warning if not "yes" or "no". If the
+ * 'element' or 'attribute' are null, the default value is returned.
+ *
+ * @param element The element to get the attribute value of
+ * @param attribute The name of the attribute to get
+ * @param defaultValue Value returned if attribute not present or invalid
+ */
+ protected boolean validateYesNoAttribute(XMLElement element, String attribute, boolean defaultValue)
+ {
+ if (element == null)
+ return defaultValue;
+
+ String value = element.getAttribute(attribute, (defaultValue ? "yes" : "no"));
+ if ("yes".equalsIgnoreCase(value))
+ return true;
+ if ("no".equalsIgnoreCase(value))
+ return false;
+
+ // TODO: should this be an error if it's present but "none of the
+ // above"?
+ parseWarn(element, "<" + element.getName() + "> invalid attribute '" + attribute
+ + "': Expected (yes|no) if present");
+
+ return defaultValue;
+ }
+
+}
\ No newline at end of file
More information about the izpack-changes
mailing list