Added subproject for the Shell GUI Plugin, which contains some plugins for
the Shell GUI bundle for a simple GUI shell for Felix.
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@391623 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.shell.gui.plugin/pom.xml b/org.apache.felix.shell.gui.plugin/pom.xml
new file mode 100644
index 0000000..121e833
--- /dev/null
+++ b/org.apache.felix.shell.gui.plugin/pom.xml
@@ -0,0 +1,61 @@
+<project>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix</artifactId>
+ <version>0.8.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>osgi-bundle</packaging>
+ <name>Apache Felix Shell GUI Plugin</name>
+ <artifactId>org.apache.felix.shell.gui.plugin</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>${pom.groupId}</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>${pom.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${pom.groupId}</groupId>
+ <artifactId>org.apache.felix.shell</artifactId>
+ <version>${pom.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${pom.groupId}</groupId>
+ <artifactId>org.apache.felix.bundlerepository</artifactId>
+ <version>${pom.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${pom.groupId}</groupId>
+ <artifactId>org.apache.felix.shell.gui</artifactId>
+ <version>${pom.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix.plugins</groupId>
+ <artifactId>maven-osgi-plugin</artifactId>
+ <version>${pom.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <osgiManifest>
+ <bundleName>ShellGUIPlugin</bundleName>
+ <bundleDescription>A simple set of plugins for the ShellGUI bundle.</bundleDescription>
+ <bundleActivator>org.apache.felix.shell.gui.plugin.Activator</bundleActivator>
+ <bundleDocUrl>http://oscar-osgi.sf.net/obr2/shellguiplugin/</bundleDocUrl>
+ <bundleUrl>http://oscar-osgi.sf.net/obr2/shellguiplugin/org.apache.felix.shell.gui.plugin.jar</bundleUrl>
+ <bundleSource>http://oscar-osgi.sf.net/obr2/shellguiplugin/org.apache.felix.shell.gui.plugin-src.jar</bundleSource>
+ <bundleSymbolicName>org.apache.felix.shell.gui.plugin</bundleSymbolicName>
+ <importPackage>org.osgi.framework,javax.swing,javax.swing.event,javax.swing.table,javax.swing.tree,javax.swing.border,javax.swing.text,org.apache.felix.shell,org.apache.felix.shell.gui,org.osgi.service.obr</importPackage>
+ <exportService>org.apache.felix.shell.gui.Plugin</exportService>
+ <importService>org.apache.felix.shell.ShellService,org.apache.felix.bundlerepository.RepostioryAdmin</importService>
+ </osgiManifest>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/Activator.java b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/Activator.java
new file mode 100644
index 0000000..b1fdeb6
--- /dev/null
+++ b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/Activator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2006 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.felix.shell.gui.plugin;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator
+{
+ private BundleContext m_context = null;
+
+ public void start(BundleContext context)
+ {
+ m_context = context;
+
+ // Register the bundle list plugin.
+ m_context.registerService(
+ org.apache.felix.shell.gui.Plugin.class.getName(),
+ new BundleListPlugin(m_context), null);
+
+ // Register the shell plugin.
+ m_context.registerService(
+ org.apache.felix.shell.gui.Plugin.class.getName(),
+ new ShellPlugin(m_context), null);
+
+ // Register the OBR plugin.
+ m_context.registerService(
+ org.apache.felix.shell.gui.Plugin.class.getName(),
+ new OBRPlugin(m_context), null);
+ }
+
+ public void stop(BundleContext context)
+ {
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/BundleListPlugin.java b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/BundleListPlugin.java
new file mode 100644
index 0000000..2933861
--- /dev/null
+++ b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/BundleListPlugin.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2006 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.felix.shell.gui.plugin;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.*;
+import javax.swing.table.AbstractTableModel;
+
+import org.apache.felix.shell.gui.Plugin;
+import org.osgi.framework.*;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class BundleListPlugin extends JPanel implements Plugin
+{
+ private BundleContext m_context = null;
+ private JTextField m_urlField = null;
+ private JButton m_installButton = null;
+ private JTable m_bundleTable = null;
+ private JButton m_startButton = null;
+ private JButton m_stopButton = null;
+ private JButton m_updateButton = null;
+ private JButton m_refreshButton = null;
+ private JButton m_uninstallButton = null;
+
+ // Plugin interface methods.
+
+ public String getName()
+ {
+ return "Bundle List";
+ }
+
+ public Component getGUI()
+ {
+ return this;
+ }
+
+ // Implementation.
+
+ public BundleListPlugin(BundleContext context)
+ {
+ m_context = context;
+
+ // Create user interface components.
+ setLayout(new BorderLayout());
+ JScrollPane scroll = null;
+ add(createURLPanel(), BorderLayout.NORTH);
+ add(scroll = new JScrollPane(m_bundleTable = new JTable()), BorderLayout.CENTER);
+ add(createButtonPanel(), BorderLayout.SOUTH);
+
+ // Set table model to display bundles.
+ m_bundleTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
+ m_bundleTable.setModel(new SimpleTableModel());
+ m_bundleTable.getColumnModel().getColumn(0).setPreferredWidth(75);
+ m_bundleTable.getColumnModel().getColumn(1).setPreferredWidth(100);
+ m_bundleTable.getColumnModel().getColumn(2).setPreferredWidth(350);
+
+ createEventListeners();
+ }
+
+ private JPanel createURLPanel()
+ {
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.add(new JLabel("URL"), BorderLayout.WEST);
+ panel.add(m_urlField = new JTextField(20), BorderLayout.CENTER);
+ panel.add(m_installButton = new JButton("Install"), BorderLayout.EAST);
+ m_installButton.setMnemonic('I');
+ return panel;
+ }
+
+ private JPanel createButtonPanel()
+ {
+ JPanel panel = new JPanel();
+ panel.add(m_startButton = new JButton("Start"));
+ panel.add(m_stopButton = new JButton("Stop"));
+ panel.add(m_updateButton = new JButton("Update"));
+ panel.add(m_refreshButton = new JButton("Refresh"));
+ panel.add(m_uninstallButton = new JButton("Uninstall"));
+ m_startButton.setMnemonic('S');
+ m_stopButton.setMnemonic('p');
+ m_updateButton.setMnemonic('a');
+ m_refreshButton.setMnemonic('R');
+ m_uninstallButton.setMnemonic('U');
+ return panel;
+ }
+
+ private void createEventListeners()
+ {
+ // Listen for bundle events in order to update
+ // the GUI bundle list.
+ BundleListener bl = new BundleListener() {
+ public void bundleChanged(BundleEvent event)
+ {
+ ((SimpleTableModel) m_bundleTable.getModel()).update();
+ }
+ };
+ m_context.addBundleListener(bl);
+
+ // Create action listeners.
+ m_installButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ if (m_urlField.getText().length() > 0)
+ {
+ try
+ {
+ m_context.installBundle(m_urlField.getText(), null);
+ }
+ catch (BundleException ex)
+ {
+ JOptionPane.showMessageDialog(
+ JOptionPane.getFrameForComponent(BundleListPlugin.this),
+ ex.getMessage(), "Error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ });
+
+ m_startButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ int[] rows = m_bundleTable.getSelectedRows();
+ for (int i = 0; i < rows.length; i++)
+ {
+ try
+ {
+ m_context.getBundles()[rows[i]].start();
+ }
+ catch (BundleException ex)
+ {
+ JOptionPane.showMessageDialog(
+ JOptionPane.getFrameForComponent(BundleListPlugin.this),
+ ex.getMessage(), "Error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ });
+
+ m_stopButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ int[] rows = m_bundleTable.getSelectedRows();
+ for (int i = 0; i < rows.length; i++)
+ {
+ try
+ {
+ m_context.getBundles()[rows[i]].stop();
+ }
+ catch (BundleException ex)
+ {
+ JOptionPane.showMessageDialog(
+ JOptionPane.getFrameForComponent(BundleListPlugin.this),
+ ex.getMessage(), "Error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ });
+
+ m_updateButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ int[] rows = m_bundleTable.getSelectedRows();
+ for (int i = 0; i < rows.length; i++)
+ {
+ try
+ {
+ m_context.getBundles()[rows[i]].update();
+ }
+ catch (BundleException ex)
+ {
+ JOptionPane.showMessageDialog(
+ JOptionPane.getFrameForComponent(BundleListPlugin.this),
+ ex.getMessage(), "Error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ });
+
+ m_refreshButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ // Get package admin service.
+ ServiceReference ref = m_context.getServiceReference(
+ PackageAdmin.class.getName());
+ if (ref == null)
+ {
+ JOptionPane.showMessageDialog(
+ JOptionPane.getFrameForComponent(BundleListPlugin.this),
+ "Unable to obtain PackageAdmin service.", "Error",
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ PackageAdmin pa = (PackageAdmin) m_context.getService(ref);
+ if (pa == null)
+ {
+ JOptionPane.showMessageDialog(
+ JOptionPane.getFrameForComponent(BundleListPlugin.this),
+ "Unable to obtain PackageAdmin service.", "Error",
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ pa.refreshPackages(null);
+ }
+ });
+
+ m_uninstallButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ int[] rows = m_bundleTable.getSelectedRows();
+ // We need to uninstall in reverse order, otherwise
+ // the index will get messed up.
+ for (int i = rows.length - 1; i >= 0; i--)
+ {
+ try
+ {
+ m_context.getBundles()[rows[i]].uninstall();
+ }
+ catch (BundleException ex)
+ {
+ JOptionPane.showMessageDialog(
+ JOptionPane.getFrameForComponent(BundleListPlugin.this),
+ ex.getMessage(), "Error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ });
+ }
+
+ private class SimpleTableModel extends AbstractTableModel
+ {
+ public int getRowCount()
+ {
+ return (m_context.getBundles() == null)
+ ? 0 : m_context.getBundles().length;
+ }
+
+ public int getColumnCount()
+ {
+ return 3;
+ }
+
+ public String getColumnName(int column)
+ {
+ if (column == 0)
+ {
+ return "Id";
+ }
+ else if (column == 1)
+ {
+ return "State";
+ }
+ else if (column == 2)
+ {
+ return "Location";
+ }
+ return "";
+ }
+
+ public Class getColumnClass(int column)
+ {
+ if (column == 0)
+ {
+ return Long.class;
+ }
+
+ return String.class;
+ }
+
+ public boolean isCellEditable(int row, int column)
+ {
+ return false;
+ }
+
+ public Object getValueAt(int row, int column)
+ {
+ if (column == 0)
+ {
+ return new Long(m_context.getBundles()[row].getBundleId());
+ }
+ else if (column == 1)
+ {
+ return getStateString(m_context.getBundles()[row].getState());
+ }
+ else if (column == 2)
+ {
+ String name = (String)
+ m_context.getBundles()[row].getHeaders().get(Constants.BUNDLE_NAME);
+ name = (name == null)
+ ? m_context.getBundles()[row].getLocation() : name;
+ return name;
+ }
+ return null;
+ }
+
+ public void update()
+ {
+ fireTableDataChanged();
+ }
+
+ private String getStateString(int state)
+ {
+ switch (state)
+ {
+ case Bundle.INSTALLED:
+ return "Installed";
+ case Bundle.RESOLVED:
+ return "Resolved";
+ case Bundle.STARTING:
+ return "Starting";
+ case Bundle.ACTIVE:
+ return "Active";
+ case Bundle.STOPPING:
+ return "Stopping";
+ }
+ return "[unknown]";
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/OBRPlugin.java b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/OBRPlugin.java
new file mode 100644
index 0000000..71d9efa
--- /dev/null
+++ b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/OBRPlugin.java
@@ -0,0 +1,728 @@
+/*
+ * Copyright 2006 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.felix.shell.gui.plugin;
+
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.PrintStream;
+import java.net.URL;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.*;
+
+import org.apache.felix.shell.gui.Plugin;
+import org.osgi.framework.*;
+import org.osgi.service.obr.*;
+
+public class OBRPlugin extends JPanel implements Plugin
+{
+ private static final String DEPLOY_BUTTON = "Deploy";
+ private static final String START_BUTTON = "Deploy & start";
+
+ private BundleContext m_context = null;
+ private ServiceReference m_repoRef = null;
+ private RepositoryAdmin m_repoAdmin = null;
+
+ private SimpleTreeNode m_rootNode = null;
+ private CreateRootRunnable m_createRootRunnable = new CreateRootRunnable();
+ private SetRootRunnable m_setRootRunnable = new SetRootRunnable();
+
+ private JButton m_addRepoButton = null;
+ private JButton m_removeRepoButton = null;
+ private JButton m_refreshRepoButton = null;
+ private JTree m_bundleTree = null;
+ private JButton m_deployButton = null;
+ private JButton m_startButton = null;
+ private JButton m_infoButton = null;
+ private ScrollableOutputArea m_soa = null;
+ private JButton m_clearButton = null;
+
+ private PrintStream m_out = null;
+
+ // Plugin interface methods.
+
+ public String getName()
+ {
+ return "OBR";
+ }
+
+ public Component getGUI()
+ {
+ return this;
+ }
+
+ // Implementation.
+
+ public OBRPlugin(BundleContext context)
+ {
+ m_context = context;
+ m_out = new PrintStream(
+ new OutputAreaStream(
+ m_soa = new ScrollableOutputArea(5, 30)));
+
+ // Create the gui.
+ createUserInterface();
+
+ synchronized (this)
+ {
+ // Listen for registering/unregistering bundle repository services.
+ ServiceListener sl = new ServiceListener() {
+ public void serviceChanged(ServiceEvent event)
+ {
+ synchronized (OBRPlugin.this)
+ {
+ // Ignore additional services if we already have one.
+ if ((event.getType() == ServiceEvent.REGISTERED)
+ && (m_repoRef != null))
+ {
+ return;
+ }
+ // Initialize the service if we don't have one.
+ else if ((event.getType() == ServiceEvent.REGISTERED)
+ && (m_repoRef == null))
+ {
+ lookupService();
+ }
+ // Unget the service if it is unregistering.
+ else if ((event.getType() == ServiceEvent.UNREGISTERING)
+ && event.getServiceReference().equals(m_repoRef))
+ {
+ m_context.ungetService(m_repoRef);
+ m_repoRef = null;
+ m_repoAdmin = null;
+ // Try to get another service.
+ lookupService();
+ }
+ }
+ }
+ };
+
+ try
+ {
+ m_context.addServiceListener(sl,
+ "(objectClass=" + RepositoryAdmin.class.getName() + ")");
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ System.err.println("OBRPlugin: " + ex);
+ }
+
+ // Now try to manually initialize the shell service
+ // since one might already be available.
+ lookupService();
+ }
+ }
+
+ private synchronized void lookupService()
+ {
+ if (m_repoAdmin != null)
+ {
+ return;
+ }
+ m_repoRef = m_context.getServiceReference(RepositoryAdmin.class.getName());
+ if (m_repoRef == null)
+ {
+ }
+ else
+ {
+ m_repoAdmin = (RepositoryAdmin) m_context.getService(m_repoRef);
+ }
+
+ // Update the model.
+ initializeRootNode();
+ }
+
+ private void createEventListeners()
+ {
+ // Create action listeners.
+ m_addRepoButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ synchronized (OBRPlugin.this)
+ {
+ if (m_repoAdmin == null)
+ {
+ return;
+ }
+
+ String s = JOptionPane.showInputDialog(
+ OBRPlugin.this, "Enter repository URL:");
+
+ if (s != null)
+ {
+ try
+ {
+ m_repoAdmin.addRepository(new URL(s));
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ // Update the table.
+ initializeRootNode();
+ }
+ }
+ });
+
+ m_removeRepoButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ synchronized (OBRPlugin.this)
+ {
+ if (m_repoAdmin == null)
+ {
+ return;
+ }
+
+ TreePath[] paths = m_bundleTree.getSelectionPaths();
+ for (int i = 0; i < paths.length; i++)
+ {
+ SimpleTreeNode node = (SimpleTreeNode) paths[i].getLastPathComponent();
+ if (node.getObject() instanceof Repository)
+ {
+ m_repoAdmin.removeRepository(
+ ((Repository)
+ ((SimpleTreeNode)
+ paths[i].getLastPathComponent()).getObject()).getURL());
+ }
+ }
+
+ // Update the table.
+ initializeRootNode();
+ }
+ }
+ });
+
+ m_refreshRepoButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ synchronized (OBRPlugin.this)
+ {
+ if (m_repoAdmin == null)
+ {
+ return;
+ }
+
+ TreePath[] paths = m_bundleTree.getSelectionPaths();
+ for (int i = 0; i < paths.length; i++)
+ {
+ SimpleTreeNode node = (SimpleTreeNode) paths[i].getLastPathComponent();
+ if (node.getObject() instanceof Repository)
+ {
+ try
+ {
+ // Adding the repository again causes it to be reparsed.
+ m_repoAdmin.addRepository(
+ ((Repository) node.getObject()).getURL());
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ // Update the table.
+ initializeRootNode();
+ }
+ }
+ });
+
+ ActionListener al = new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ boolean start = event.getActionCommand().equals(START_BUTTON);
+
+ synchronized (OBRPlugin.this)
+ {
+ if (m_repoAdmin == null)
+ {
+ return;
+ }
+
+ Resolver resolver = m_repoAdmin.resolver();
+ TreePath[] paths = m_bundleTree.getSelectionPaths();
+ for (int i = 0; i < paths.length; i++)
+ {
+ SimpleTreeNode node = (SimpleTreeNode) paths[i].getLastPathComponent();
+ if (node.getObject() instanceof Resource)
+ {
+ resolver.add((Resource) node.getObject());
+ }
+ }
+
+ if ((resolver.getAddedResources() != null) &&
+ (resolver.getAddedResources().length > 0))
+ {
+ if (resolver.resolve())
+ {
+ m_out.println("Target resource(s):");
+ printUnderline(m_out, 19);
+ Resource[] resources = resolver.getAddedResources();
+ for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
+ {
+ m_out.println(" " + resources[resIdx].getPresentationName()
+ + " (" + resources[resIdx].getVersion() + ")");
+ }
+ resources = resolver.getRequiredResources();
+ if ((resources != null) && (resources.length > 0))
+ {
+ m_out.println("\nRequired resource(s):");
+ printUnderline(m_out, 21);
+ for (int resIdx = 0; resIdx < resources.length; resIdx++)
+ {
+ m_out.println(" " + resources[resIdx].getPresentationName()
+ + " (" + resources[resIdx].getVersion() + ")");
+ }
+ }
+ resources = resolver.getOptionalResources();
+ if ((resources != null) && (resources.length > 0))
+ {
+ m_out.println("\nOptional resource(s):");
+ printUnderline(m_out, 21);
+ for (int resIdx = 0; resIdx < resources.length; resIdx++)
+ {
+ m_out.println(" " + resources[resIdx].getPresentationName()
+ + " (" + resources[resIdx].getVersion() + ")");
+ }
+ }
+
+ try
+ {
+ m_out.print("\nDeploying...");
+ resolver.deploy(start);
+ m_out.println("done.");
+ }
+ catch (IllegalStateException ex)
+ {
+ m_out.println(ex);
+ }
+ }
+ else
+ {
+ Requirement[] reqs = resolver.getUnsatisfiedRequirements();
+ if ((reqs != null) && (reqs.length > 0))
+ {
+ m_out.println("Unsatisfied requirement(s):");
+ printUnderline(m_out, 27);
+ for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++)
+ {
+ m_out.println(" " + reqs[reqIdx].getFilter());
+ Resource[] resources = resolver.getResources(reqs[reqIdx]);
+ for (int resIdx = 0; resIdx < resources.length; resIdx++)
+ {
+ m_out.println(" " + resources[resIdx].getPresentationName());
+ }
+ }
+ }
+ else
+ {
+ m_out.println("Could not resolve targets.");
+ }
+ }
+
+ m_out.println("");
+ }
+ }
+ }
+ };
+
+ m_deployButton.addActionListener(al);
+ m_startButton.addActionListener(al);
+
+ m_infoButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ synchronized (OBRPlugin.this)
+ {
+ if (m_repoAdmin == null)
+ {
+ return;
+ }
+ TreePath[] paths = m_bundleTree.getSelectionPaths();
+ for (int i = 0; i < paths.length; i++)
+ {
+ if (i != 0)
+ {
+ m_out.println("");
+ }
+ printInfo(m_out,
+ ((SimpleTreeNode) paths[i].getLastPathComponent()).getObject());
+ }
+ m_out.println("");
+ }
+ }
+ });
+
+ m_clearButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent event)
+ {
+ synchronized (OBRPlugin.this)
+ {
+ m_soa.setText("");
+ }
+ }
+ });
+
+ m_bundleTree.addTreeSelectionListener(new TreeSelectionListener() {
+ public void valueChanged(TreeSelectionEvent e)
+ {
+ if (m_repoAdmin == null)
+ {
+ return;
+ }
+ TreePath[] paths = m_bundleTree.getSelectionPaths();
+ boolean repoOnly = true;
+ if (paths != null)
+ {
+ for (int i = 0; repoOnly && (i < paths.length); i++)
+ {
+ SimpleTreeNode node = (SimpleTreeNode) paths[i].getLastPathComponent();
+ if (!(node.getObject() instanceof Repository))
+ {
+ repoOnly = false;
+ }
+ }
+ }
+ m_removeRepoButton.setEnabled((paths != null) && repoOnly);
+ m_refreshRepoButton.setEnabled((paths != null) && repoOnly);
+ m_infoButton.setEnabled((paths != null) && (paths.length > 0));
+ }
+ });
+ }
+
+ private void printInfo(PrintStream out, Object obj)
+ {
+ if (obj != null)
+ {
+ if (obj instanceof Repository)
+ {
+ Repository repo = (Repository) obj;
+ out.println(repo.getName());
+ out.println(" URL = " + repo.getURL());
+ out.println(" Modified = " + new Date(repo.getLastModified()));
+ }
+ else if (obj instanceof Resource)
+ {
+ Resource res = (Resource) obj;
+ out.println(res.getPresentationName());
+
+ // Print properties.
+ Map map = res.getProperties();
+ Iterator iter = map.entrySet().iterator();
+ while (iter.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) iter.next();
+ out.println(" " + entry.getKey() + " = " + entry.getValue());
+ }
+
+ // Print requirements.
+ Requirement[] reqs = res.getRequirements();
+ for (int i = 0; (reqs != null) && (i < reqs.length); i++)
+ {
+ if (i == 0)
+ {
+ out.println(" requirements:");
+ }
+ out.println(" " + reqs[i].getFilter());
+ }
+
+ // Print capabilities.
+ Capability[] caps = res.getCapabilities();
+ for (int i = 0; (caps != null) && (i < caps.length); i++)
+ {
+ if (i == 0)
+ {
+ out.println(" capabilities:");
+ }
+ out.println(" " + caps[i].getName() + " = " + caps[i].getProperties());
+ }
+ }
+ }
+ }
+
+ private void createUserInterface()
+ {
+ JSplitPane split = new JSplitPane(
+ JSplitPane.VERTICAL_SPLIT, createTree(), createConsole());
+ split.setResizeWeight(1.0);
+ split.setDividerSize(5);
+ setLayout(new BorderLayout());
+ add(split, BorderLayout.CENTER);
+ createEventListeners();
+ }
+
+ private JPanel createTree()
+ {
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.add(createRepoPanel(), BorderLayout.NORTH);
+ panel.add(createResourcePanel(), BorderLayout.CENTER);
+ return panel;
+ }
+
+ private JPanel createRepoPanel()
+ {
+ JPanel panel = new JPanel();
+ panel.setBorder(BorderFactory.createTitledBorder("Repositories"));
+ panel.add(m_addRepoButton = new JButton("Add"));
+ m_addRepoButton.setMnemonic('A');
+ panel.add(m_removeRepoButton = new JButton("Remove"));
+ m_removeRepoButton.setMnemonic('R');
+ panel.add(m_refreshRepoButton = new JButton("Refresh"));
+ m_refreshRepoButton.setMnemonic('f');
+ m_removeRepoButton.setEnabled(false);
+ m_refreshRepoButton.setEnabled(false);
+ return panel;
+ }
+
+ private JPanel createResourcePanel()
+ {
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.setBorder(BorderFactory.createTitledBorder("Resources"));
+ JScrollPane scroll = null;
+ panel.add(
+ scroll = new JScrollPane(
+ m_bundleTree = new JTree(new SimpleTreeNode(null, null))), BorderLayout.CENTER);
+ panel.add(createButtonPanel(), BorderLayout.SOUTH);
+
+ // Set table scroll pane to reasonable size.
+ scroll.setPreferredSize(new Dimension(100, 100));
+ m_bundleTree.setMinimumSize(new Dimension(0, 0));
+
+ // We don't need to see the root.
+ m_bundleTree.setRootVisible(false);
+ m_bundleTree.setShowsRootHandles(true);
+
+ return panel;
+ }
+
+ private JPanel createButtonPanel()
+ {
+ JPanel panel = new JPanel();
+ panel.add(m_deployButton = new JButton(DEPLOY_BUTTON));
+ panel.add(m_startButton = new JButton(START_BUTTON));
+ panel.add(m_infoButton = new JButton("Info"));
+ m_deployButton.setMnemonic('D');
+ m_startButton.setMnemonic('S');
+ m_infoButton.setMnemonic('I');
+ m_infoButton.setEnabled(false);
+ return panel;
+ }
+
+ private JPanel createConsole()
+ {
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.add(m_soa, BorderLayout.CENTER);
+ panel.add(m_clearButton = new JButton("Clear"), BorderLayout.EAST);
+ m_clearButton.setMnemonic('C');
+
+ return panel;
+ }
+
+ private static void printUnderline(PrintStream out, int length)
+ {
+ for (int i = 0; i < length; i++)
+ {
+ out.print('-');
+ }
+ out.println("");
+ }
+
+ private void initializeRootNode()
+ {
+ synchronized (m_createRootRunnable)
+ {
+ new Thread(m_createRootRunnable).start();
+ }
+ }
+
+ private class CreateRootRunnable implements Runnable
+ {
+ public void run()
+ {
+ synchronized (OBRPlugin.this)
+ {
+ // HACK ALERT: This next if statement is a hack to force
+ // the OBR service to retrieve its repository files on
+ // this thread, rather than the Swing thread. This hack
+ // assumes that this GUI is working with Felix' OBR service,
+ // which defers retrieving repository URLs until needed.
+ if (m_repoAdmin != null)
+ {
+ m_repoAdmin.listRepositories();
+ }
+
+ // Create the new root node and then set it.
+ m_rootNode = new SimpleTreeNode(null, m_repoAdmin);
+ try
+ {
+ SwingUtilities.invokeAndWait(m_setRootRunnable);
+ }
+ catch (Exception ex)
+ {
+ // Ignore.
+ }
+ }
+ }
+ }
+
+ private class SetRootRunnable implements Runnable
+ {
+ public void run()
+ {
+ ((DefaultTreeModel) m_bundleTree.getModel()).setRoot(m_rootNode);
+ }
+ }
+
+ private static class SimpleTreeNode implements TreeNode
+ {
+ private TreeNode m_parent = null;
+ private Object m_obj = null;
+ private TreeNode[] m_children = null;
+ private String m_toString = null;
+
+ public SimpleTreeNode(TreeNode parent, Object obj)
+ {
+ m_parent = parent;
+ m_obj = obj;
+ }
+
+ public Object getObject()
+ {
+ return m_obj;
+ }
+
+ public TreeNode getChildAt(int index)
+ {
+ if (m_children == null)
+ {
+ initialize();
+ }
+
+ if ((m_children != null) && (index >= 0) && (index < m_children.length))
+ {
+ return m_children[index];
+ }
+
+ return null;
+ }
+
+ public int getChildCount()
+ {
+ if (m_children == null)
+ {
+ initialize();
+ }
+ return (m_children == null) ? 0 : m_children.length;
+ }
+
+ public TreeNode getParent()
+ {
+ return m_parent;
+ }
+
+ public int getIndex(TreeNode node)
+ {
+ if (m_children == null)
+ {
+ initialize();
+ }
+ for (int i = 0; (m_children != null) && (i < m_children.length); i++)
+ {
+ if (m_children[i] == node)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public boolean getAllowsChildren()
+ {
+ return true;
+ }
+
+ public boolean isLeaf()
+ {
+ return (getChildCount() == 0);
+ }
+
+ public Enumeration children()
+ {
+ return null;
+ }
+
+ private void initialize()
+ {
+ // The current node might be the root repository admin.
+ if ((m_obj != null) && (m_obj instanceof RepositoryAdmin))
+ {
+ Object[] objs = ((RepositoryAdmin) m_obj).listRepositories();
+ if (objs != null)
+ {
+ m_children = new TreeNode[objs.length];
+ for (int i = 0; i < objs.length; i++)
+ {
+ m_children[i] = new SimpleTreeNode(this, objs[i]);
+ }
+ }
+ }
+ else if (m_obj instanceof Repository)
+ {
+ Object[] objs = ((Repository) m_obj).getResources();
+ if (objs != null)
+ {
+ m_children = new TreeNode[objs.length];
+ for (int i = 0; i < objs.length; i++)
+ {
+ m_children[i] = new SimpleTreeNode(this, objs[i]);
+ }
+ }
+ }
+ }
+
+ public String toString()
+ {
+ if (m_toString == null)
+ {
+ if (m_obj instanceof RepositoryAdmin)
+ {
+ m_toString = "ROOT";
+ }
+ else if (m_obj instanceof Repository)
+ {
+ m_toString = ((Repository) m_obj).getName();
+ }
+ else if (m_obj instanceof Resource)
+ {
+ m_toString = ((Resource) m_obj).getPresentationName()
+ + " (" + ((Resource) m_obj).getVersion() + ")";
+ }
+ else
+ {
+ m_toString = (m_obj != null) ? m_obj.toString() : "null";
+ }
+ }
+ return m_toString;
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/OutputAreaStream.java b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/OutputAreaStream.java
new file mode 100644
index 0000000..992b673
--- /dev/null
+++ b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/OutputAreaStream.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2006 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.felix.shell.gui.plugin;
+
+import java.io.OutputStream;
+
+class OutputAreaStream extends OutputStream
+{
+ private ScrollableOutputArea m_soa;
+
+ public OutputAreaStream(ScrollableOutputArea soa)
+ {
+ m_soa = soa;
+ }
+
+ public void write(byte[] b)
+ {
+ String tmp = new String(b);
+ m_soa.addText(tmp);
+ }
+
+ public void write(byte[] b, int off, int len)
+ {
+ String tmp = new String(b, off, len);
+ m_soa.addText(tmp);
+ }
+
+ public void write(int b)
+ {
+ byte[] ba = { (byte) b };
+ m_soa.addText(new String(ba));
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/ScrollableOutputArea.java b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/ScrollableOutputArea.java
new file mode 100644
index 0000000..c454e51
--- /dev/null
+++ b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/ScrollableOutputArea.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2006 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.felix.shell.gui.plugin;
+
+import java.awt.Font;
+
+import javax.swing.*;
+
+public class ScrollableOutputArea extends JScrollPane
+{
+ private JTextArea m_textArea = null;
+
+ public ScrollableOutputArea()
+ {
+ super();
+ m_textArea = new JTextArea();
+ initialize();
+ }
+
+ public ScrollableOutputArea(int rows, int columns)
+ {
+ super();
+ m_textArea = new JTextArea(rows, columns);
+ initialize();
+ }
+
+ private void initialize()
+ {
+ setViewportView(m_textArea);
+ m_textArea.setLineWrap(true);
+ m_textArea.setAutoscrolls(true);
+ m_textArea.setEnabled(true);
+ m_textArea.setEditable(false);
+ m_textArea.setFont(new Font("Monospaced", 0, 12));
+ setAutoscrolls(true);
+ }
+
+ public void setText(String s)
+ {
+ m_textArea.setText(s);
+ }
+
+ public void addText(String text)
+ {
+ m_textArea.append(text);
+ if (m_textArea.isDisplayable())
+ {
+ try
+ {
+ m_textArea.setCaretPosition(Integer.MAX_VALUE); // Scroll to end of window
+ }
+ catch (Exception e)
+ {
+ // Just for safety
+ }
+ }
+ validate();
+ JScrollBar sb = getVerticalScrollBar();
+ if ((sb != null) && (sb.isVisible()))
+ {
+ sb.setValue(Integer.MAX_VALUE);
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/ShellPlugin.java b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/ShellPlugin.java
new file mode 100644
index 0000000..aaaba36
--- /dev/null
+++ b/org.apache.felix.shell.gui.plugin/src/main/java/org/apache/felix/shell/gui/plugin/ShellPlugin.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2006 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.felix.shell.gui.plugin;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.io.PrintStream;
+
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import org.apache.felix.shell.ShellService;
+import org.apache.felix.shell.gui.Plugin;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public class ShellPlugin extends JPanel implements Plugin
+{
+ private BundleContext m_context = null;
+ private PrintStream m_out = null;
+
+ private JTextField m_commandField = new JTextField();
+ private String[] m_history = new String[25];
+ private int m_historyCount = -1;
+ private int m_current = 0; // current history counter
+
+ private ScrollableOutputArea m_soa = new ScrollableOutputArea();
+
+ // Plugin interface methods.
+
+ public String getName()
+ {
+ return "Shell";
+ }
+
+ public Component getGUI()
+ {
+ return this;
+ }
+
+ // Implementation.
+
+ public ShellPlugin(BundleContext context)
+ {
+ m_context = context;
+ m_out = new PrintStream(new OutputAreaStream(m_soa));
+ initialize();
+ }
+
+ private void initialize()
+ {
+ setLayout(new BorderLayout());
+ m_commandField.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent event)
+ {
+ commandFieldKeyPressed(event);
+ }
+ });
+ m_commandField.setFont(new java.awt.Font("Monospaced", 0, 12));
+ add(m_commandField, BorderLayout.SOUTH);
+ add(m_soa, BorderLayout.CENTER);
+ }
+
+ void processCommand(String line)
+ {
+ if (line == null)
+ {
+ return;
+ }
+
+ line = line.trim();
+
+ if (line.length() == 0)
+ {
+ return;
+ }
+
+ // Get shell service.
+ ServiceReference ref = m_context.getServiceReference(
+ org.apache.felix.shell.ShellService.class.getName());
+ if (ref == null)
+ {
+ m_out.println("No shell service is available.");
+ return;
+ }
+
+ ShellService shell = (ShellService) m_context.getService(ref);
+
+ // Print the command line in the output window.
+ m_out.println("-> " + line);
+
+ try {
+ shell.executeCommand(line, m_out, m_out);
+ } catch (Exception ex) {
+ m_out.println(ex.toString());
+ ex.printStackTrace(m_out);
+ }
+
+ m_context.ungetService(ref);
+ }
+
+ private void addToHistory(String command)
+ {
+ m_historyCount++;
+ if (m_historyCount >= m_history.length)
+ {
+ m_historyCount = m_history.length - 1;
+ for (int i = 0; i < m_history.length - 1; i++)
+ {
+ m_history[i] = m_history[i + 1];
+ }
+ }
+ m_history[m_historyCount] = new String(command);
+ }
+
+ private String getFromHistory(int num)
+ {
+ if (num < 0)
+ {
+ return ("");
+ }
+ else if (num > m_historyCount)
+ {
+ return("");
+ }
+ return m_history[num];
+ }
+
+ protected void commandFieldKeyPressed(KeyEvent event)
+ {
+ String command = null;
+ int c = event.getKeyCode();
+ // Cursor up.
+ if (c == 38)
+ {
+ m_current--;
+ if (m_current < 0)
+ {
+ m_current = 0;
+ }
+ m_commandField.setText(getFromHistory(m_current));
+ m_commandField.setCaretPosition(m_commandField.getText().length());
+ }
+ // Cursor down.
+ else if (c == 40)
+ {
+ m_current++;
+ if (m_current > m_historyCount)
+ {
+ m_current = m_historyCount + 1;
+ }
+ m_commandField.setText(getFromHistory(m_current));
+ m_commandField.setCaretPosition(m_commandField.getText().length());
+ }
+ else if (c == 10)
+ {
+ command = m_commandField.getText();
+ if (!command.equals(""))
+ {
+ addToHistory(command);
+ m_current = m_historyCount + 1;
+ processCommand(command);
+ }
+ m_commandField.setText("");
+ }
+ }
+}
\ No newline at end of file