You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2005/08/16 20:34:41 UTC

svn commit: r233031 [9/21] - in /incubator/oscar/trunk: ./ etc/ lib/ src/ src/org/ src/org/apache/ src/org/apache/osgi/ src/org/apache/osgi/bundle/ src/org/apache/osgi/bundle/bundlerepository/ src/org/apache/osgi/bundle/bundlerepository/kxmlsax/ src/or...

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/cache/DefaultBundleCache.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/cache/DefaultBundleCache.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/cache/DefaultBundleCache.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/cache/DefaultBundleCache.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,262 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.cache;
+
+import java.io.*;
+
+import org.apache.osgi.framework.LogWrapper;
+import org.apache.osgi.framework.util.PropertyResolver;
+
+/**
+ * <p>
+ * This class, combined with <tt>DefaultBundleArchive</tt>, implements the
+ * default file system-based bundle cache for Felix. It is possible to
+ * configure the default behavior of this class by passing properties into
+ * Felix constructor. The configuration properties for this class are:
+ * </p>
+ * <ul>
+ *   <li><tt>felix.cache.bufsize</tt> - Sets the buffer size to be used by
+ *       the cache; the default value is 4096. The integer
+ *       value of this string provides control over the size of the
+ *       internal buffer of the disk cache for performance reasons.
+ *   </li>
+ *   <li><tt>felix.cache.dir</tt> - Sets the directory to be used by the
+ *       cache as its cache directory. The cache directory is where all
+ *       profile directories are stored and a profile directory is where a
+ *       set of installed bundles are stored. By default, the cache
+ *       directory is <tt>.felix</tt> in the user's home directory. If
+ *       this property is specified, then its value will be used as the cache
+ *       directory instead of <tt>.felix</tt>. This directory will be created
+ *       if it does not exist.
+ *   </li>
+ *   <li><tt>felix.cache.profile</tt> - Sets the profile name that will be
+ *       used to create a profile directory inside of the cache directory.
+ *       The created directory will contained all installed bundles associated
+ *       with the profile.
+ *   </li>
+ *   <li><tt>felix.cache.profiledir</tt> - Sets the directory to use as the
+ *       profile directory for the bundle cache; by default the profile
+ *       name is used to create a directory in the <tt>.felix</tt> cache
+ *       directory. If this property is specified, then the cache directory
+ *       and profile name properties are ignored. The specified value of this
+ *       property is used directly as the directory to contain all cached
+ *       bundles. If this property is set, it is not necessary to set the
+ *       cache directory or profile name properties. This directory will be
+ *       created if it does not exist.
+ *   </li>
+ * </ul>
+ * <p>
+ * For specific information on how to configure Felix using system properties,
+ * refer to the Felix usage documentation.
+ * </p>
+ * @see org.apache.osgi.framework.util.DefaultBundleArchive
+**/
+public class DefaultBundleCache implements BundleCache
+{
+    public static final String CACHE_BUFSIZE_PROP = "felix.cache.bufsize";
+    public static final String CACHE_DIR_PROP = "felix.cache.dir";
+    public static final String CACHE_PROFILE_DIR_PROP = "felix.cache.profiledir";
+    public static final String CACHE_PROFILE_PROP = "felix.cache.profile";
+
+    protected static transient int BUFSIZE = 4096;
+    protected static transient final String CACHE_DIR_NAME = ".felix";
+    protected static transient final String BUNDLE_DIR_PREFIX = "bundle";
+
+    private PropertyResolver m_cfg = null;
+    private LogWrapper m_logger = null;
+    private File m_profileDir = null;
+    private BundleArchive[] m_archives = null;
+
+    public DefaultBundleCache()
+    {
+    }
+
+    public void initialize(PropertyResolver cfg, LogWrapper logger) throws Exception
+    {
+        // Save Properties reference.
+        m_cfg = cfg;
+        // Save LogService reference.
+        m_logger = logger;
+
+        // Get buffer size value.
+        try
+        {
+            String sBufSize = m_cfg.get(CACHE_BUFSIZE_PROP);
+            if (sBufSize != null)
+            {
+                BUFSIZE = Integer.parseInt(sBufSize);
+            }
+        }
+        catch (NumberFormatException ne)
+        {
+            // Use the default value.
+        }
+
+        // See if the profile directory is specified.
+        String profileDirStr = m_cfg.get(CACHE_PROFILE_DIR_PROP);
+        if (profileDirStr != null)
+        {
+            m_profileDir = new File(profileDirStr);
+        }
+        else
+        {
+            // Since no profile directory was specified, then the profile
+            // directory will be a directory in the cache directory named
+            // after the profile.
+
+            // First, determine the location of the cache directory; it
+            // can either be specified or in the default location.
+            String cacheDirStr = m_cfg.get(CACHE_DIR_PROP);
+            if (cacheDirStr == null)
+            {
+                // Since no cache directory was specified, put it
+                // ".felix" in the user's home by default.
+                cacheDirStr = System.getProperty("user.home");
+                cacheDirStr = cacheDirStr.endsWith(File.separator)
+                    ? cacheDirStr : cacheDirStr + File.separator;
+                cacheDirStr = cacheDirStr + CACHE_DIR_NAME;
+            }
+
+            // Now, get the profile name.
+            String profileName = m_cfg.get(CACHE_PROFILE_PROP);
+            if (profileName == null)
+            {
+                throw new IllegalArgumentException(
+                    "No profile name or directory has been specified.");
+            }
+            // Profile name cannot contain the File.separator char.
+            else if (profileName.indexOf(File.separator) >= 0)
+            {
+                throw new IllegalArgumentException(
+                    "The profile name cannot contain the file separator character.");
+            }
+
+            m_profileDir = new File(cacheDirStr, profileName);
+        }
+
+        // Create profile directory.
+        if (!m_profileDir.exists())
+        {
+            if (!m_profileDir.mkdirs())
+            {
+                m_logger.log(
+                    LogWrapper.LOG_ERROR,
+                    "Unable to create directory: " + m_profileDir);
+                throw new RuntimeException("Unable to create profile directory.");
+            }
+        }
+
+        // Create the existing bundle archives in the profile directory,
+        // if any exist.
+        File[] children = m_profileDir.listFiles();
+        int count = 0;
+        for (int i = 0; (children != null) && (i < children.length); i++)
+        {
+            // Count the legitimate bundle directories.
+            if (children[i].getName().startsWith(BUNDLE_DIR_PREFIX))
+            {
+                count++;
+            }
+        }
+        m_archives = new BundleArchive[count];
+        count = 0;
+        for (int i = 0; (children != null) && (i < children.length); i++)
+        {
+            // Ignore directories that aren't bundle directories.
+            if (children[i].getName().startsWith(BUNDLE_DIR_PREFIX))
+            {
+                String id = children[i].getName().substring(BUNDLE_DIR_PREFIX.length());
+                m_archives[count] = new DefaultBundleArchive(
+                    m_logger, children[i], Long.parseLong(id));
+                count++;
+            }
+        }
+    }
+
+    public BundleArchive[] getArchives()
+        throws Exception
+    {
+        return m_archives;
+    }
+
+    public BundleArchive getArchive(long id)
+        throws Exception
+    {
+        for (int i = 0; i < m_archives.length; i++)
+        {
+            if (m_archives[i].getId() == id)
+            {
+                return m_archives[i];
+            }
+        }
+        return null;
+    }
+
+    public BundleArchive create(long id, String location, InputStream is)
+        throws Exception
+    {
+        // Define new bundle's directory.
+        File bundleDir = new File(m_profileDir, "bundle" + id);
+
+        try
+        {
+            // Buffer the input stream.
+            is = new BufferedInputStream(is, DefaultBundleCache.BUFSIZE);
+            // Create an archive instance for the new bundle.
+            BundleArchive ba = new DefaultBundleArchive(
+                m_logger, bundleDir, id, location, is);
+            // Add the archive instance to the list of bundle archives.
+            BundleArchive[] bas = new BundleArchive[m_archives.length + 1];
+            System.arraycopy(m_archives, 0, bas, 0, m_archives.length);
+            bas[m_archives.length] = ba;
+            m_archives = bas;
+            return ba;
+        }
+        finally
+        {
+            if (is != null) is.close();
+        }
+    }
+
+    public void update(BundleArchive ba, InputStream is)
+        throws Exception
+    {
+        try
+        {
+            // Buffer the input stream.
+            is = new BufferedInputStream(is, DefaultBundleCache.BUFSIZE);
+            // Do the update.
+            ((DefaultBundleArchive) ba).update(is);
+        }
+        finally
+        {
+            if (is != null) is.close();
+        }
+    }
+
+    public void purge(BundleArchive ba)
+        throws Exception
+    {
+        ((DefaultBundleArchive) ba).purge();
+    }
+
+    public void remove(BundleArchive ba)
+        throws Exception
+    {
+        ((DefaultBundleArchive) ba).remove();
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/ext/FelixBundleContext.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/ext/FelixBundleContext.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/ext/FelixBundleContext.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/ext/FelixBundleContext.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,28 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.ext;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+
+public interface FelixBundleContext extends BundleContext
+{
+    public void addImportPackage() throws BundleException;
+    public void removeImportPackage() throws BundleException;
+    public void addExportPackage() throws BundleException;
+    public void removeExportPackage() throws BundleException;
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Artifact.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Artifact.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Artifact.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Artifact.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,30 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+public interface Artifact
+{
+    public StringProperty getSourceName();
+    public StringProperty getDestinationDirectory();
+    public InputStream getInputStream(Status status) throws IOException;
+    public boolean localize();
+    public boolean process(Status status, Map propMap);
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/BooleanProperty.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/BooleanProperty.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/BooleanProperty.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/BooleanProperty.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,23 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer;
+
+public interface BooleanProperty extends Property
+{
+    public boolean getBooleanValue();
+    public void setBooleanValue(boolean b);
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Install.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Install.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Install.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Install.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,431 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.border.BevelBorder;
+
+import org.apache.osgi.framework.installer.artifact.*;
+import org.apache.osgi.framework.installer.editor.BooleanEditor;
+import org.apache.osgi.framework.installer.editor.FileEditor;
+import org.apache.osgi.framework.installer.property.*;
+import org.apache.osgi.framework.util.FelixConstants;
+
+public class Install extends JFrame
+{
+    private static transient final String PROPERTY_FILE = "property.xml";
+    private static transient final String ARTIFACT_FILE = "artifact.xml";
+
+    public static transient final String JAVA_DIR = "Java directory";
+    public static transient final String INSTALL_DIR = "Install directory";
+
+    private PropertyPanel m_propPanel = null;
+    private JButton m_okayButton = null;
+    private JButton m_cancelButton = null;
+    private JLabel m_statusLabel = null;
+
+    private java.util.List m_propList = null;
+    private java.util.List m_artifactList = null;
+
+    public Install()
+        throws Exception
+    {
+        super("Install");
+
+        // Load properties before resources, because resources
+        // refer to properties.
+        m_propList = loadPropertyList();
+        m_artifactList = loadArtifactList();
+
+        getContentPane().setLayout(new BorderLayout());
+        getContentPane().add(
+            m_propPanel = new PropertyPanel(m_propList), BorderLayout.CENTER);
+        getContentPane().add(createButtonPanel(), BorderLayout.SOUTH);
+        pack();
+        setResizable(true);
+        centerWindow(this);
+
+        // Make window closeable.
+        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent event)
+            {
+                doCancel();
+            }
+        });
+    }
+
+    public java.util.List loadPropertyList()
+    {
+        String installDir = System.getProperty("user.home");
+        if (!installDir.endsWith(File.separator))
+        {
+            installDir = installDir + File.separator;
+        }
+
+        Property prop = null;
+
+        // Eventually these should be read from a file.
+        java.util.List list = new ArrayList();
+
+        // Add the shell choice property.
+        prop = new BooleanPropertyImpl("Shell", true);
+        prop.setEditor(new BooleanEditor((BooleanProperty) prop, "Text", "GUI"));
+        list.add(prop);
+
+        // Add the java directory property.
+        prop = new StringPropertyImpl(JAVA_DIR, System.getProperty("java.home"));
+        prop.setEditor(new FileEditor((StringProperty) prop, true));
+        list.add(prop);
+
+        // Add the installation directory property.
+        prop = new StringPropertyImpl(INSTALL_DIR, installDir + "Felix");
+        prop.setEditor(new FileEditor((StringProperty) prop, true));
+        list.add(prop);
+
+        // Add the documentation URL property.
+        prop = new BooleanStringPropertyImpl(
+            "User documentation",
+            true,
+            "http://download.forge.objectweb.org/oscar/oscar-doc-"
+            + FelixConstants.FELIX_VERSION_VALUE + ".jar");
+        list.add(prop);
+
+        // Add the documentation URL property.
+        prop = new BooleanStringPropertyImpl(
+            "API documentation",
+            true,
+            "http://download.forge.objectweb.org/oscar/oscar-api-"
+            + FelixConstants.FELIX_VERSION_VALUE + ".jar");
+        list.add(prop);
+
+        return list;
+    }
+
+    public java.util.List loadArtifactList() throws Exception
+    {
+        // Eventually I will changed these to be read from a file.
+        java.util.List list = new ArrayList();
+        list.add(
+            new ArtifactHolder(
+                (BooleanProperty) getProperty("User documentation"),
+                new URLJarArtifact(
+                    (StringProperty) getProperty("User documentation"))));
+        list.add(
+            new ArtifactHolder(
+                (BooleanProperty) getProperty("API documentation"),
+                new URLJarArtifact(
+                    (StringProperty) getProperty("API documentation"))));
+        list.add(
+            new ArtifactHolder(
+                new ResourceJarArtifact(
+                    new StringPropertyImpl("sourceName", "package.jar"))));
+        list.add(
+            new ArtifactHolder(
+                new ResourceFileArtifact(
+                    new StringPropertyImpl("sourceName", "src.jar"))));
+        list.add(
+            new ArtifactHolder(
+                new ResourceFileArtifact(
+                    new StringPropertyImpl("sourceName", "LICENSE.txt"))));
+        list.add(
+            new ArtifactHolder(
+                (BooleanProperty) getProperty("Shell"),
+                new ResourceFileArtifact(
+                    new StringPropertyImpl("sourceName", "config.properties.text"),
+                    new StringPropertyImpl("destName", "config.properties"),
+                    new StringPropertyImpl("destDir", "lib"))));
+        list.add(
+            new ArtifactHolder(
+                new NotBooleanPropertyImpl((BooleanProperty) getProperty("Shell")),
+                new ResourceFileArtifact(
+                    new StringPropertyImpl("sourceName", "config.properties.gui"),
+                    new StringPropertyImpl("destName", "config.properties"),
+                    new StringPropertyImpl("destDir", "lib"))));
+        list.add(
+            new ArtifactHolder(
+                new ResourceFileArtifact(
+                    new StringPropertyImpl("sourceName", "example.policy"))));
+        list.add(
+            new ArtifactHolder(
+                new ResourceFileArtifact(
+                    new StringPropertyImpl("sourceName", "felix.bat"),
+                    new StringPropertyImpl("destName" , "felix.bat"),
+                    new StringPropertyImpl("destDir", ""),
+                    true)));
+        list.add(
+            new ArtifactHolder(
+                new ResourceFileArtifact(
+                    new StringPropertyImpl("sourceName", "felix.sh"),
+                    new StringPropertyImpl("destName" , "felix.sh"),
+                    new StringPropertyImpl("destDir", ""),
+                    true)));
+
+        return list;
+    }
+
+    private Property getProperty(String name)
+    {
+        for (int i = 0; i < m_propList.size(); i++)
+        {
+            Property prop = (Property) m_propList.get(i);
+            if (prop.getName().equals(name))
+            {
+                return prop;
+            }
+        }
+        return null;
+    }
+
+    protected void doOkay()
+    {
+        m_propPanel.setEnabled(false);
+        m_okayButton.setEnabled(false);
+        m_cancelButton.setEnabled(false);
+        new Thread(new InstallRunnable()).start();
+    }
+
+    protected void doCancel()
+    {
+        System.exit(0);
+    }
+
+    protected JPanel createButtonPanel()
+    {
+        JPanel buttonPanel = new JPanel();
+        buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
+
+        // Create and set layout.
+        GridBagLayout grid = new GridBagLayout();
+        GridBagConstraints c = new GridBagConstraints();
+
+        buttonPanel.setLayout(grid);
+
+        // Create labels and fields.
+        c.insets = new Insets(2, 2, 2, 2);
+
+        // Okay button.
+        c.gridx = 0;
+        c.gridy = 0;
+        c.gridwidth = 1;
+        c.gridheight = 1;
+        c.anchor = GridBagConstraints.EAST;
+        grid.setConstraints(m_okayButton = new JButton("OK"), c);
+        buttonPanel.add(m_okayButton);
+        m_okayButton.setDefaultCapable(true);
+        getRootPane().setDefaultButton(m_okayButton);
+
+        // Cancel button.
+        c.gridx = 1;
+        c.gridy = 0;
+        c.gridwidth = 1;
+        c.gridheight = 1;
+        c.anchor = GridBagConstraints.WEST;
+        grid.setConstraints(m_cancelButton = new JButton("Cancel"), c);
+        buttonPanel.add(m_cancelButton);
+
+        // Add action listeners.
+        m_okayButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event)
+            {
+                doOkay();
+            }
+        });
+
+        m_cancelButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event)
+            {
+                doCancel();
+            }
+        });
+
+        // Status label.
+        m_statusLabel = new JLabel("Felix installation");
+        m_statusLabel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+
+        // Complete panel.
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.add(buttonPanel, BorderLayout.CENTER);
+        panel.add(m_statusLabel, BorderLayout.SOUTH);
+        return panel;
+    }
+
+    public static void centerWindow(Component window)
+    {
+        Toolkit toolkit = Toolkit.getDefaultToolkit();
+        Dimension dim = toolkit.getScreenSize();
+        int screenWidth = dim.width;
+        int screenHeight = dim.height;
+        int x = (screenWidth - window.getSize().width) / 2;
+        int y = (screenHeight - window.getSize().height) / 2;
+        window.setLocation(x, y);
+    }
+
+    public static void main(String[] argv) throws Exception
+    {
+        String msg = "<html>"
+            + "<center><h1>Felix " + FelixConstants.FELIX_VERSION_VALUE + "</h1></center>"
+            + "You can download example bundles at the Felix shell prompt by<br>"
+            + "using the <b><tt>obr</tt></b> command to access the OSGi Bundle Repository;<br>"
+            + "type <b><tt>obr help</tt></b> at the Felix shell prompt for details."
+            + "</html>";
+        JLabel label = new JLabel(msg);
+        label.setFont(new Font("SansSerif", Font.PLAIN, 11));
+        final JDialog dlg = new JDialog((Frame) null, "Felix Install", true);
+        dlg.getContentPane().setLayout(new BorderLayout(10, 10));
+        dlg.getContentPane().add(label, BorderLayout.CENTER);
+        JPanel panel = new JPanel();
+        JButton button = new JButton("OK");
+        button.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event)
+            {
+                dlg.hide();
+            }
+        });
+        panel.add(button);
+        dlg.getContentPane().add(panel, BorderLayout.SOUTH);
+        // For spacing purposes...
+        dlg.getContentPane().add(new JPanel(), BorderLayout.NORTH);
+        dlg.getContentPane().add(new JPanel(), BorderLayout.EAST);
+        dlg.getContentPane().add(new JPanel(), BorderLayout.WEST);
+        dlg.pack();
+        centerWindow(dlg);
+        dlg.show();
+
+        Install obj = new Install();
+        obj.setVisible(true);
+    }
+
+    class InstallRunnable implements Runnable
+    {
+        public void run()
+        {
+            Map propMap = new HashMap();
+            for (int i = 0; i < m_propList.size(); i++)
+            {
+                Property prop = (Property) m_propList.get(i);
+                propMap.put(prop.getName(), prop);
+            }
+
+            String installDir = ((StringProperty) propMap.get(INSTALL_DIR)).getStringValue();
+
+            // Make sure the install directory ends with separator char.
+            if (!installDir.endsWith(File.separator))
+            {
+                installDir = installDir + File.separator;
+            }
+
+            // Make sure the install directory exists and
+            // that is actually a directory.
+            File file = new File(installDir);
+            if (!file.exists())
+            {
+                if (!file.mkdirs())
+                {
+                    JOptionPane.showMessageDialog(Install.this,
+                        "Unable to create install directory.",
+                        "Error", JOptionPane.ERROR_MESSAGE);
+                    System.exit(-1);
+                }
+            }
+            else if (!file.isDirectory())
+            {
+                JOptionPane.showMessageDialog(Install.this,
+                    "The selected install location is not a directory.",
+                    "Error", JOptionPane.ERROR_MESSAGE);
+                System.exit(-1);
+            }
+
+            // Status updater runnable.
+            StatusRunnable sr = new StatusRunnable();
+
+            // Loop through and process resources.
+            for (int i = 0; i < m_artifactList.size(); i++)
+            {
+                ArtifactHolder ah = (ArtifactHolder) m_artifactList.get(i);
+                if (ah.isIncluded())
+                {
+                    if (!ah.getArtifact().process(sr, propMap))
+                    {
+                        JOptionPane.showMessageDialog(Install.this,
+                            "An error occurred while processing the resources.",
+                            "Error", JOptionPane.ERROR_MESSAGE);
+                        System.exit(-1);
+                    }
+                }
+            }
+
+            System.exit(0);
+        }
+    }
+
+    class StatusRunnable implements Status, Runnable
+    {
+        private String text = null;
+
+        public void setText(String s)
+        {
+            text = s;
+            try {
+                SwingUtilities.invokeAndWait(this);
+            } catch (Exception ex) {
+                // Ignore.
+            }
+        }
+
+        public void run()
+        {
+            m_statusLabel.setText(text);
+        }
+    }
+
+    // Re-usable static member for ResourceHolder inner class.
+    private static BooleanProperty m_trueProp =
+        new BooleanPropertyImpl("mandatory", true);
+
+    class ArtifactHolder
+    {
+        private BooleanProperty m_isIncluded = null;
+        private Artifact m_artifact = null;
+        
+        public ArtifactHolder(Artifact artifact)
+        {
+            this(m_trueProp, artifact);
+        }
+        
+        public ArtifactHolder(BooleanProperty isIncluded, Artifact artifact)
+        {
+            m_isIncluded = isIncluded;
+            m_artifact = artifact;
+        }
+        
+        public boolean isIncluded()
+        {
+            return m_isIncluded.getBooleanValue();
+        }
+        
+        public Artifact getArtifact()
+        {
+            return m_artifact;
+        }
+    }
+}

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Property.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Property.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Property.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Property.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,27 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer;
+
+import javax.swing.JComponent;
+
+public interface Property
+{
+    public String getName();
+    public JComponent getEditor();
+    public void setEditor(JComponent comp);
+    public String toString();
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/PropertyPanel.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/PropertyPanel.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/PropertyPanel.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/PropertyPanel.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,87 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+
+public class PropertyPanel extends JPanel
+{
+    private List m_propList = null;
+    private Map m_propToCompMap = null;
+
+    public PropertyPanel(List paramList)
+    {
+        super();
+        m_propList = paramList;
+        m_propToCompMap = new HashMap();
+        layoutComponents();
+    }
+
+    public void setEnabled(boolean b)
+    {
+        for (int i = 0; i < m_propList.size(); i++)
+        {
+            Property prop = (Property) m_propList.get(i);
+            JComponent comp = (JComponent) m_propToCompMap.get(prop.getName());
+            comp.setEnabled(b);
+        }
+    }
+
+    public List getProperties()
+    {
+        return m_propList;
+    }
+
+    protected void layoutComponents()
+    {
+        // Create the field panel for entering query variables.
+        GridBagLayout grid = new GridBagLayout();
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.insets = new Insets(2, 2, 2, 2);
+        setLayout(grid);
+
+        for (int i = 0; i < m_propList.size(); i++)
+        {
+            Property prop = (Property) m_propList.get(i);
+            JLabel label = null;
+            JComponent component = null;
+
+            // Add label.
+            gbc.gridx = 0;
+            gbc.gridy = i;
+            gbc.gridheight = 1;
+            gbc.gridwidth = 1;
+            gbc.anchor = GridBagConstraints.EAST;
+            grid.setConstraints(label = new JLabel(prop.getName()), gbc);
+            add(label);
+
+            gbc.gridx = 1;
+            gbc.gridy = i;
+            gbc.gridheight = 1;
+            gbc.gridwidth = 3;
+            gbc.anchor = GridBagConstraints.WEST;
+            grid.setConstraints(component = prop.getEditor(), gbc);
+            add(component);
+
+            m_propToCompMap.put(prop.getName(), component);
+        }
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Status.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Status.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Status.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/Status.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,22 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer;
+
+public interface Status
+{
+    public void setText(String s);
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/StringProperty.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/StringProperty.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/StringProperty.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/StringProperty.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,23 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer;
+
+public interface StringProperty extends Property
+{
+    public String getStringValue();
+    public void setStringValue(String s);
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractArtifact.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractArtifact.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractArtifact.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractArtifact.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,230 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.artifact;
+
+import java.io.*;
+import java.util.Map;
+
+import org.apache.osgi.framework.installer.*;
+import org.apache.osgi.framework.installer.property.StringPropertyImpl;
+
+public abstract class AbstractArtifact implements Artifact
+{
+    private StringProperty m_sourceName = null;
+    private StringProperty m_destDir = null;
+    private boolean m_localize = false;
+
+    // This following shared buffer assumes that there is
+    // no concurrency when processing resources.
+    protected static byte[] s_buffer = new byte[2048];
+
+    public AbstractArtifact(
+        StringProperty sourceName, StringProperty destDir, boolean localize)
+    {
+        if (destDir == null)
+        {
+            destDir = new StringPropertyImpl("empty", "");
+        }
+        m_sourceName = sourceName;
+        m_destDir = destDir;
+        m_localize = localize;
+    }
+
+    public StringProperty getSourceName()
+    {
+        return m_sourceName;
+    }
+
+    public StringProperty getDestinationDirectory()
+    {
+        return m_destDir;
+    }
+
+    public boolean localize()
+    {
+        return m_localize;
+    }
+
+    protected static void copy(
+        InputStream is, String installDir, String destName, String destDir)
+        throws IOException
+    {
+        if (destDir == null)
+        {
+            destDir = "";
+        }
+
+        // Make sure the target directory exists and
+        // that is actually a directory.
+        File targetDir = new File(installDir, destDir);
+        if (!targetDir.exists())
+        {
+            if (!targetDir.mkdirs())
+            {
+                throw new IOException("Unable to create target directory: "
+                    + targetDir);
+            }
+        }
+        else if (!targetDir.isDirectory())
+        {
+            throw new IOException("Target is not a directory: "
+                + targetDir);
+        }
+
+        BufferedOutputStream bos = new BufferedOutputStream(
+            new FileOutputStream(new File(targetDir, destName)));
+        int count = 0;
+        while ((count = is.read(s_buffer)) > 0)
+        {
+            bos.write(s_buffer, 0, count);
+        }
+        bos.close();
+    }
+
+    protected static void copyAndLocalize(
+        InputStream is, String installDir, String destName,
+        String destDir, Map propMap)
+        throws IOException
+    {
+        if (destDir == null)
+        {
+            destDir = "";
+        }
+
+        // Make sure the target directory exists and
+        // that is actually a directory.
+        File targetDir = new File(installDir, destDir);
+        if (!targetDir.exists())
+        {
+            if (!targetDir.mkdirs())
+            {
+                throw new IOException("Unable to create target directory: "
+                    + targetDir);
+            }
+        }
+        else if (!targetDir.isDirectory())
+        {
+            throw new IOException("Target is not a directory: "
+                + targetDir);
+        }
+
+        BufferedOutputStream bos = new BufferedOutputStream(
+            new FileOutputStream(new File(targetDir, destName)));
+        int i = 0;
+        while ((i = is.read()) > 0)
+        {
+            // Parameters start with "%%", so check to see if
+            // we have a parameter.
+            if ((char)i == '%')
+            {
+                // One of three possibilities, we have a parameter,
+                // we have an end of file, or we don't have a parameter.
+                int i2 = is.read();
+                if ((char) i2 == '%')
+                {
+                    Object obj = readParameter(is);
+
+                    // If the byte sequence was not a parameter afterall,
+                    // then a byte array is returned, otherwise a string
+                    // containing the parameter m_name is returned.
+                    if (obj instanceof byte[])
+                    {
+                        bos.write(i);
+                        bos.write(i2);
+                        bos.write((byte[]) obj);
+                    }
+                    else
+                    {
+                        Property prop = (Property) propMap.get(obj);
+                        String value = (prop == null) ? "" : prop.toString();
+                        bos.write(value.getBytes());
+                    }
+                }
+                else if (i2 == -1)
+                {
+                    bos.write(i);
+                }
+                else
+                {
+                    bos.write(i);
+                    bos.write(i2);
+                }
+            }
+            else
+            {
+                bos.write(i);
+            }
+        }
+        bos.close();
+    }
+
+    protected static Object readParameter(InputStream is)
+        throws IOException
+    {
+        int count = 0;
+        int i = 0;
+        while ((count < s_buffer.length) && ((i = is.read()) > 0))
+        {
+            if ((char) i == '%')
+            {
+                // One of three possibilities, we have the end of
+                // the parameter, we have an end of file, or we
+                // don't have the parameter end.
+                int i2 = is.read();
+                if ((char) i2 == '%')
+                {
+                    return new String(s_buffer, 0, count);
+                }
+                else if (i2 == -1)
+                {
+                    s_buffer[count] = (byte) i;
+                    byte[] b = new byte[count];
+                    for (int j = 0; j < count; j++)
+                        b[j] = s_buffer[j];
+                    return b;
+                }
+                else
+                {
+                    s_buffer[count++] = (byte) i;
+                    s_buffer[count++] = (byte) i2;
+                }
+            }
+            else
+            {
+                s_buffer[count++] = (byte) i;
+            }
+        }
+
+        byte[] b = new byte[count - 1];
+        for (int j = 0; j < (count - 1); j++)
+            b[j] = s_buffer[j];
+
+        return b;
+    }
+
+    public static String getPath(String s, char separator)
+    {
+        return (s.lastIndexOf(separator) < 0)
+            ? "" : s.substring(0, s.lastIndexOf(separator));
+    }
+
+    public static String getPathHead(String s, char separator)
+    {
+        return (s.lastIndexOf(separator) < 0)
+            ? s : s.substring(s.lastIndexOf(separator) + 1);
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractFileArtifact.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractFileArtifact.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractFileArtifact.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractFileArtifact.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,103 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.artifact;
+
+import java.io.InputStream;
+import java.util.Map;
+
+import org.apache.osgi.framework.installer.*;
+
+public abstract class AbstractFileArtifact extends AbstractArtifact
+{
+    private StringProperty m_destName = null;
+
+    public AbstractFileArtifact(StringProperty sourceName)
+    {
+        this(sourceName, sourceName);
+    }
+
+    public AbstractFileArtifact(StringProperty sourceName, StringProperty destName)
+    {
+        this(sourceName, destName, null);
+    }
+
+    public AbstractFileArtifact(
+        StringProperty sourceName, StringProperty destName, StringProperty destDir)
+    {
+        this(sourceName, destName, destDir, false);
+    }
+
+    public AbstractFileArtifact(
+        StringProperty sourceName, StringProperty destName,
+        StringProperty destDir, boolean localize)
+    {
+        super(sourceName, destDir, localize);
+        m_destName = destName;
+    }
+
+    public StringProperty getDestinationName()
+    {
+        return m_destName;
+    }
+
+    public boolean process(Status status, Map propMap)
+    {
+        String installDir =
+            ((StringProperty) propMap.get(Install.INSTALL_DIR)).getStringValue();
+
+        try
+        {
+            InputStream is = getInputStream(status);
+
+            if (is == null)
+            {
+                return true;
+            }
+
+            if (localize())
+            {
+                status.setText("Copying and configuring "
+                    + getSourceName().getStringValue());
+                copyAndLocalize(
+                    is,
+                    installDir,
+                    getDestinationName().getStringValue(),
+                    getDestinationDirectory().getStringValue(),
+                    propMap);
+            }
+            else
+            {
+                status.setText("Copying " + getSourceName().getStringValue());
+                copy(
+                    is,
+                    installDir,
+                    getDestinationName().getStringValue(),
+                    getDestinationDirectory().getStringValue());
+            }
+
+            is.close();
+
+        }
+        catch (Exception ex)
+        {
+            System.err.println(ex);
+            return false;
+        }
+
+        return true;
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractJarArtifact.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractJarArtifact.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractJarArtifact.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/AbstractJarArtifact.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,124 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.artifact;
+
+import java.io.*;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+import org.apache.osgi.framework.installer.*;
+
+public abstract class AbstractJarArtifact extends AbstractArtifact
+{
+    public AbstractJarArtifact(StringProperty sourceName)
+    {
+        this(sourceName, null);
+    }
+
+    public AbstractJarArtifact(StringProperty sourceName, StringProperty destDir)
+    {
+        this(sourceName, destDir, false);
+    }
+
+    public AbstractJarArtifact(
+        StringProperty sourceName, StringProperty destDir, boolean localize)
+    {
+        super(sourceName, destDir, localize);
+    }
+
+    public boolean process(Status status, Map propMap)
+    {
+        try
+        {
+            InputStream is = getInputStream(status);
+
+            if (is == null)
+            {
+                return true;
+            }
+
+            JarInputStream jis = new JarInputStream(is);
+            status.setText("Extracting...");
+            unjar(jis, propMap);
+            jis.close();
+        }
+        catch (Exception ex)
+        {
+            System.err.println(this);
+            System.err.println(ex);
+            return false;
+        }
+
+        return true;
+    }
+
+    protected void unjar(JarInputStream jis, Map propMap)
+        throws IOException
+    {
+        String installDir =
+            ((StringProperty) propMap.get(Install.INSTALL_DIR)).getStringValue();
+
+        // Loop through JAR entries.
+        for (JarEntry je = jis.getNextJarEntry();
+             je != null;
+             je = jis.getNextJarEntry())
+        {
+            if (je.getName().startsWith("/"))
+            {
+                throw new IOException("JAR resource cannot contain absolute paths.");
+            }
+
+            File target =
+                new File(installDir, getDestinationDirectory().getStringValue());
+            target = new File(target, je.getName());
+
+            // Check to see if the JAR entry is a directory.
+            if (je.isDirectory())
+            {
+                if (!target.exists())
+                {
+                    if (!target.mkdirs())
+                    {
+                        throw new IOException("Unable to create target directory: "
+                            + target);
+                    }
+                }
+                // Just continue since directories do not have content to copy.
+                continue;
+            }
+
+            int lastIndex = je.getName().lastIndexOf('/');
+            String name = (lastIndex >= 0) ?
+                je.getName().substring(lastIndex + 1) : je.getName();
+            String destination = (lastIndex >= 0) ?
+                je.getName().substring(0, lastIndex) : "";
+
+            // JAR files use '/', so convert it to platform separator.
+            destination = destination.replace('/', File.separatorChar);
+
+            if (localize())
+            {
+                copyAndLocalize(jis, installDir, name, destination, propMap);
+            }
+            else
+            {
+                copy(jis, installDir, name, destination);
+            }
+        }
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/ResourceFileArtifact.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/ResourceFileArtifact.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/ResourceFileArtifact.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/ResourceFileArtifact.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,61 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.artifact;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.osgi.framework.installer.Status;
+import org.apache.osgi.framework.installer.StringProperty;
+import org.apache.osgi.framework.installer.resource.ResourceLoader;
+
+public class ResourceFileArtifact extends AbstractFileArtifact
+{
+    public ResourceFileArtifact(StringProperty sourceName)
+    {
+        this(sourceName, sourceName);
+    }
+
+    public ResourceFileArtifact(StringProperty sourceName, StringProperty destName)
+    {
+        this(sourceName, destName, null);
+    }
+
+    public ResourceFileArtifact(
+        StringProperty sourceName, StringProperty destName, StringProperty destDir)
+    {
+        this(sourceName, destName, destDir, false);
+    }
+
+    public ResourceFileArtifact(
+        StringProperty sourceName, StringProperty destName,
+        StringProperty destDir, boolean localize)
+    {
+        super(sourceName, destName, destDir, localize);
+    }
+
+    public InputStream getInputStream(Status status)
+        throws IOException
+    {
+        return ResourceLoader.getResourceAsStream(getSourceName().getStringValue());
+    }
+
+    public String toString()
+    {
+        return "RESOURCE FILE: " + getSourceName().getStringValue();
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/ResourceJarArtifact.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/ResourceJarArtifact.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/ResourceJarArtifact.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/ResourceJarArtifact.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,54 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.artifact;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.osgi.framework.installer.Status;
+import org.apache.osgi.framework.installer.StringProperty;
+import org.apache.osgi.framework.installer.resource.ResourceLoader;
+
+public class ResourceJarArtifact extends AbstractJarArtifact
+{
+    public ResourceJarArtifact(StringProperty sourceName)
+    {
+        this(sourceName, null);
+    }
+
+    public ResourceJarArtifact(StringProperty sourceName, StringProperty destDir)
+    {
+        this(sourceName, destDir, false);
+    }
+
+    public ResourceJarArtifact(
+        StringProperty sourceName, StringProperty destDir, boolean localize)
+    {
+        super(sourceName, destDir, localize);
+    }
+
+    public InputStream getInputStream(Status status)
+        throws IOException
+    {
+        return ResourceLoader.getResourceAsStream(getSourceName().getStringValue());
+    }
+
+    public String toString()
+    {
+        return "RESOURCE JAR: " + getSourceName().getStringValue();
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/URLFileArtifact.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/URLFileArtifact.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/URLFileArtifact.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/URLFileArtifact.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,90 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.artifact;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.apache.osgi.framework.installer.Status;
+import org.apache.osgi.framework.installer.StringProperty;
+
+public class URLFileArtifact extends AbstractFileArtifact
+{
+    public URLFileArtifact(StringProperty sourceName, StringProperty destName)
+    {
+        this(sourceName, destName, null);
+    }
+
+    public URLFileArtifact(
+        StringProperty sourceName, StringProperty destName, StringProperty destDir)
+    {
+        this(sourceName, destName, destDir, false);
+    }
+
+    public URLFileArtifact(
+        StringProperty sourceName, StringProperty destName,
+        StringProperty destDir, boolean localize)
+    {
+        super(sourceName, destName, destDir, localize);
+    }
+
+    public InputStream getInputStream(Status status)
+        throws IOException
+    {
+        String fileName = getSourceName().getStringValue();
+        fileName = (fileName.lastIndexOf('/') > 0)
+            ? fileName.substring(fileName.lastIndexOf('/') + 1)
+            : fileName;
+        
+        status.setText("Connecting...");
+
+        File file = File.createTempFile("felix-install.tmp", null);
+        file.deleteOnExit();
+
+        OutputStream os = new FileOutputStream(file);
+        URLConnection conn = new URL(getSourceName().getStringValue()).openConnection();
+        int total = conn.getContentLength();
+        InputStream is = conn.getInputStream();
+
+        int count = 0;
+        for (int len = is.read(s_buffer); len > 0; len = is.read(s_buffer))
+        {
+            count += len;
+            os.write(s_buffer, 0, len);
+            if (total > 0)
+            {
+                status.setText("Downloading " + fileName
+                    + " ( " + count + " bytes of " + total + " ).");
+            }
+            else
+            {
+                status.setText("Downloading " + fileName + " ( " + count + " bytes ).");
+            }
+        }
+
+        os.close();
+        is.close();
+
+        return new FileInputStream(file);
+    }
+
+    public String toString()
+    {
+        return "URL FILE: " + getSourceName().getStringValue();
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/URLJarArtifact.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/URLJarArtifact.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/URLJarArtifact.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/artifact/URLJarArtifact.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,88 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.artifact;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.apache.osgi.framework.installer.Status;
+import org.apache.osgi.framework.installer.StringProperty;
+
+public class URLJarArtifact extends AbstractJarArtifact
+{
+    public URLJarArtifact(StringProperty sourceName)
+    {
+        this(sourceName, null);
+    }
+
+    public URLJarArtifact(StringProperty sourceName, StringProperty destDir)
+    {
+        this(sourceName, destDir, false);
+    }
+
+    public URLJarArtifact(
+        StringProperty sourceName, StringProperty destDir, boolean localize)
+    {
+        super(sourceName, destDir, localize);
+    }
+
+    public InputStream getInputStream(Status status)
+        throws IOException
+    {
+        String fileName = getSourceName().getStringValue();
+        fileName = (fileName.lastIndexOf('/') > 0)
+            ? fileName.substring(fileName.lastIndexOf('/') + 1)
+            : fileName;
+        
+        status.setText("Connecting...");
+
+        File file = File.createTempFile("felix-install.tmp", null);
+        file.deleteOnExit();
+
+        OutputStream os = new FileOutputStream(file);
+        URLConnection conn = new URL(getSourceName().getStringValue()).openConnection();
+        int total = conn.getContentLength();
+        InputStream is = conn.getInputStream();
+
+        int count = 0;
+        for (int len = is.read(s_buffer); len > 0; len = is.read(s_buffer))
+        {
+            count += len;
+            os.write(s_buffer, 0, len);
+            if (total > 0)
+            {
+                status.setText("Downloading " + fileName
+                    + " ( " + count + " bytes of " + total + " ).");
+            }
+            else
+            {
+                status.setText("Downloading " + fileName + " ( " + count + " bytes ).");
+            }
+        }
+
+        os.close();
+        is.close();
+
+        return new FileInputStream(file);
+    }
+
+    public String toString()
+    {
+        return "URL JAR: " + getSourceName().getStringValue();
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/BooleanEditor.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/BooleanEditor.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/BooleanEditor.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/BooleanEditor.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,89 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.editor;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.*;
+
+import org.apache.osgi.framework.installer.BooleanProperty;
+import org.apache.osgi.framework.installer.Property;
+
+public class BooleanEditor extends JPanel
+{
+    private BooleanProperty m_prop = null;
+    private JRadioButton m_trueButton = null;
+    private JRadioButton m_falseButton = null;
+    private String m_trueString = null;
+    private String m_falseString = null;
+
+    public BooleanEditor(BooleanProperty prop)
+    {
+        this(prop, "true", "false");
+    }
+
+    public BooleanEditor(BooleanProperty prop, String trueString, String falseString)
+    {
+        m_prop = prop;
+        m_trueString = trueString;
+        m_falseString = falseString;
+        init();
+    }
+
+    public Property getProperty()
+    {
+        return m_prop;
+    }
+
+    public void setEnabled(boolean b)
+    {
+        m_trueButton.setEnabled(b);
+        m_falseButton.setEnabled(b);
+    }
+
+    protected void init()
+    {
+        add(m_trueButton = new JRadioButton(m_trueString));
+        add(m_falseButton = new JRadioButton(m_falseString));
+        ButtonGroup group = new ButtonGroup();
+        group.add(m_trueButton);
+        group.add(m_falseButton);
+        if (m_prop.getBooleanValue())
+        {
+            m_trueButton.setSelected(true);
+        }
+        else
+        {
+            m_falseButton.setSelected(true);
+        }
+
+        // Add action listeners.
+        m_trueButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event)
+            {
+                m_prop.setBooleanValue(true);
+            }
+        });
+        m_falseButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event)
+            {
+                m_prop.setBooleanValue(false);
+            }
+        });
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/BooleanStringEditor.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/BooleanStringEditor.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/BooleanStringEditor.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/BooleanStringEditor.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,125 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.editor;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import org.apache.osgi.framework.installer.*;
+
+public class BooleanStringEditor extends JPanel
+{
+    private Property m_prop = null;
+    private JCheckBox m_includeButton = null;
+    private JTextField m_textField = null;
+
+    public BooleanStringEditor(Property prop)
+    {
+        if ((prop instanceof BooleanProperty) && (prop instanceof StringProperty))
+        {
+            m_prop = prop;
+        }
+        else
+        {
+            throw new IllegalArgumentException(
+                "Property must implement both boolean and string property interfaces.");
+        }
+        init();
+    }
+
+    public Property getProperty()
+    {
+        return m_prop;
+    }
+
+    public void setEnabled(boolean b)
+    {
+        m_includeButton.setEnabled(b);
+        m_textField.setEnabled(b && m_includeButton.isSelected());
+    }
+
+    protected void init()
+    {
+        // Set layout.
+        GridBagLayout grid = new GridBagLayout();
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.insets = new Insets(0, 2, 0, 2);
+        setLayout(grid);
+
+        // Add button.
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.gridheight = 1;
+        gbc.gridwidth = 1;
+        gbc.anchor = GridBagConstraints.WEST;
+        m_includeButton = new JCheckBox("");
+        grid.setConstraints(m_includeButton, gbc);
+        add(m_includeButton);
+
+        // Add field.
+        gbc.gridx = 1;
+        gbc.gridy = 0;
+        gbc.gridheight = 1;
+        gbc.gridwidth = 3;
+        gbc.anchor = GridBagConstraints.WEST;
+        m_textField = new JTextField(30);
+        m_textField.setText(((StringProperty) m_prop).getStringValue());
+        grid.setConstraints(m_textField, gbc);
+        add(m_textField);
+        m_textField.setEnabled(false);
+
+        // Add action listener.
+        m_includeButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event)
+            {
+                if (m_includeButton.isSelected())
+                {
+                    ((BooleanProperty) m_prop).setBooleanValue(true);
+                    m_textField.setEnabled(true);
+                }
+                else
+                {
+                    ((BooleanProperty) m_prop).setBooleanValue(false);
+                    m_textField.setEnabled(false);
+                }
+            }
+        });
+
+        // Add focus listener.
+        m_textField.addFocusListener(new FocusListener() {
+            public void focusGained(FocusEvent event)
+            {
+            }
+            public void focusLost(FocusEvent event)
+            {
+                if (!event.isTemporary())
+                {
+                    ((StringProperty) m_prop).setStringValue(m_textField.getText());
+                }
+            }
+        });
+
+        // Currently, the button is not selected. If the property
+        // is true, then click once to select button.        
+        if (((BooleanProperty) m_prop).getBooleanValue())
+        {
+            m_includeButton.doClick();
+        }
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/FileEditor.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/FileEditor.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/FileEditor.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/FileEditor.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,139 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.editor;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+
+import javax.swing.*;
+
+import org.apache.osgi.framework.installer.Property;
+import org.apache.osgi.framework.installer.StringProperty;
+
+public class FileEditor extends JPanel
+{
+    private StringProperty m_prop = null;
+    private JTextField m_textField = null;
+    private JButton m_browseButton = null;
+    private boolean m_isDirectory = false;
+
+    public FileEditor(StringProperty prop, boolean isDirectory)
+    {
+        super();
+        m_prop = prop;
+        m_isDirectory = isDirectory;
+        init();
+    }
+
+    public Property getProperty()
+    {
+        return m_prop;
+    }
+
+    public void setEnabled(boolean b)
+    {
+        m_textField.setEnabled(b);
+        m_browseButton.setEnabled(b);
+    }
+
+    protected void init()
+    {
+        // Set layout.
+        GridBagLayout grid = new GridBagLayout();
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.insets = new Insets(0, 2, 0, 2);
+        setLayout(grid);
+
+        // Add field.
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.gridheight = 1;
+        gbc.gridwidth = 2;
+        gbc.anchor = GridBagConstraints.WEST;
+        m_textField = new JTextField(30);
+        m_textField.setText(m_prop.getStringValue());
+        grid.setConstraints(m_textField, gbc);
+        add(m_textField);
+
+        // Add button.
+        gbc.gridx = 2;
+        gbc.gridy = 0;
+        gbc.gridheight = 1;
+        gbc.gridwidth = 1;
+        gbc.anchor = GridBagConstraints.EAST;
+        m_browseButton = new JButton("Browse...");
+        m_browseButton.setMargin(new Insets(1, 1, 1, 1));
+        grid.setConstraints(m_browseButton, gbc);
+        add(m_browseButton);
+
+        // Add focus listener.
+        m_textField.addFocusListener(new FocusListener() {
+            public void focusGained(FocusEvent event)
+            {
+            }
+            public void focusLost(FocusEvent event)
+            {
+                if (!event.isTemporary())
+                {
+                    // Set the new value.
+                    m_prop.setStringValue(normalizeValue(m_textField.getText()));
+
+                }
+            }
+        });
+
+        // Add action listener.
+        m_browseButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event)
+            {
+                JFileChooser fileDlg = new JFileChooser();
+                if (m_isDirectory)
+                {
+                    fileDlg.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+                    fileDlg.setDialogTitle("Please select a directory...");
+                }
+                else
+                {
+                    fileDlg.setFileSelectionMode(JFileChooser.FILES_ONLY);
+                    fileDlg.setDialogTitle("Please select a file...");
+                }
+                fileDlg.setApproveButtonText("Select");
+                if (fileDlg.showOpenDialog(FileEditor.this) ==
+                    JFileChooser.APPROVE_OPTION)
+                {
+                    m_textField.setText(fileDlg.getSelectedFile().getAbsolutePath());
+                    m_prop.setStringValue(normalizeValue(m_textField.getText()));
+                }
+            }
+        });
+    }
+
+    private String normalizeValue(String value)
+    {
+        // Make sure that directories never end with a slash,
+        // for consistency.
+        if (m_isDirectory)
+        {
+            if (value.endsWith(File.separator))
+            {
+                value = value.substring(0, value.length() - 1);
+            }
+        }
+        return value;
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/StringEditor.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/StringEditor.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/StringEditor.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/editor/StringEditor.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,83 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.editor;
+
+import java.awt.*;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import org.apache.osgi.framework.installer.Property;
+import org.apache.osgi.framework.installer.StringProperty;
+
+public class StringEditor extends JPanel
+{
+    private StringProperty m_prop = null;
+    private JTextField m_textField = null;
+
+    public StringEditor(StringProperty prop)
+    {
+        m_prop = prop;
+        init();
+    }
+
+    public Property getProperty()
+    {
+        return m_prop;
+    }
+
+    public void setEnabled(boolean b)
+    {
+        m_textField.setEnabled(b);
+    }
+
+    protected void init()
+    {
+        // Set layout.
+        GridBagLayout grid = new GridBagLayout();
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.insets = new Insets(0, 2, 0, 2);
+        setLayout(grid);
+
+        // Add field.
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.gridheight = 1;
+        gbc.gridwidth = 2;
+        gbc.anchor = GridBagConstraints.WEST;
+        m_textField = new JTextField(20);
+        m_textField.setText(m_prop.getStringValue());
+        grid.setConstraints(m_textField, gbc);
+        add(m_textField);
+
+        // Add focus listener.
+        m_textField.addFocusListener(new FocusListener() {
+            public void focusGained(FocusEvent event)
+            {
+            }
+            public void focusLost(FocusEvent event)
+            {
+                if (!event.isTemporary())
+                {
+                    m_prop.setStringValue(m_textField.getText());
+                }
+            }
+        });
+    }
+}

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/manifest.mf
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/manifest.mf?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/manifest.mf (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/manifest.mf Tue Aug 16 11:33:34 2005
@@ -0,0 +1 @@
+Main-Class: org.apache.osgi.framework.installer.Install

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/BooleanPropertyImpl.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/BooleanPropertyImpl.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/BooleanPropertyImpl.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/BooleanPropertyImpl.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,69 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.property;
+
+import javax.swing.JComponent;
+
+import org.apache.osgi.framework.installer.BooleanProperty;
+import org.apache.osgi.framework.installer.editor.BooleanEditor;
+
+public class BooleanPropertyImpl implements BooleanProperty
+{
+    private String m_name = null;
+    private boolean m_value = false;
+    private JComponent m_editor = null;
+
+    public BooleanPropertyImpl(String name, boolean value)
+    {
+        m_name = name;
+        m_value = value;
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public boolean getBooleanValue()
+    {
+        return m_value;
+    }
+
+    public void setBooleanValue(boolean b)
+    {
+        m_value = b;
+    }
+
+    public JComponent getEditor()
+    {
+        if (m_editor == null)
+        {
+            m_editor = new BooleanEditor(this);
+        }
+        return m_editor;
+    }
+
+    public void setEditor(JComponent comp)
+    {
+        m_editor = comp;
+    }
+
+    public String toString()
+    {
+        return (m_value) ? Boolean.TRUE.toString() : Boolean.FALSE.toString();
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/BooleanStringPropertyImpl.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/BooleanStringPropertyImpl.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/BooleanStringPropertyImpl.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/BooleanStringPropertyImpl.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,82 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.property;
+
+import javax.swing.JComponent;
+
+import org.apache.osgi.framework.installer.BooleanProperty;
+import org.apache.osgi.framework.installer.StringProperty;
+import org.apache.osgi.framework.installer.editor.BooleanStringEditor;
+
+public class BooleanStringPropertyImpl implements BooleanProperty, StringProperty
+{
+    private String m_name = null;
+    private boolean m_boolean = false;
+    private String m_string = "";
+    private JComponent m_editor = null;
+
+    public BooleanStringPropertyImpl(String name, boolean b, String s)
+    {
+        m_name = name;
+        m_boolean = b;
+        m_string = s;
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public boolean getBooleanValue()
+    {
+        return m_boolean;
+    }
+
+    public void setBooleanValue(boolean b)
+    {
+        m_boolean = b;
+    }
+
+    public String getStringValue()
+    {
+        return m_string;
+    }
+
+    public void setStringValue(String s)
+    {
+        m_string = s;
+    }
+
+    public JComponent getEditor()
+    {
+        if (m_editor == null)
+        {
+            m_editor = new BooleanStringEditor(this);
+        }
+        return m_editor;
+    }
+
+    public void setEditor(JComponent comp)
+    {
+        m_editor = comp;
+    }
+
+    public String toString()
+    {
+        return m_string;
+    }
+}
\ No newline at end of file

Added: incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/NotBooleanPropertyImpl.java
URL: http://svn.apache.org/viewcvs/incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/NotBooleanPropertyImpl.java?rev=233031&view=auto
==============================================================================
--- incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/NotBooleanPropertyImpl.java (added)
+++ incubator/oscar/trunk/src/org/apache/osgi/framework/installer/property/NotBooleanPropertyImpl.java Tue Aug 16 11:33:34 2005
@@ -0,0 +1,67 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.osgi.framework.installer.property;
+
+import javax.swing.JComponent;
+
+import org.apache.osgi.framework.installer.BooleanProperty;
+import org.apache.osgi.framework.installer.editor.BooleanEditor;
+
+public class NotBooleanPropertyImpl implements BooleanProperty
+{
+    private BooleanProperty m_prop = null;
+    private JComponent m_editor = null;
+
+    public NotBooleanPropertyImpl(BooleanProperty prop)
+    {
+        m_prop = prop;
+    }
+
+    public String getName()
+    {
+        return "NOT " + m_prop.getName();
+    }
+
+    public boolean getBooleanValue()
+    {
+        return !m_prop.getBooleanValue();
+    }
+
+    public void setBooleanValue(boolean b)
+    {
+        m_prop.setBooleanValue(!b);
+    }
+
+    public JComponent getEditor()
+    {
+        if (m_editor == null)
+        {
+            m_editor = new BooleanEditor(this);
+        }
+        return m_editor;
+    }
+
+    public void setEditor(JComponent comp)
+    {
+        m_editor = comp;
+    }
+
+    public String toString()
+    {
+        return (getBooleanValue()) ? Boolean.TRUE.toString() : Boolean.FALSE.toString();
+    }
+}
\ No newline at end of file