commit e3c1a1eea587f7fc0333906e8a93037d233e95d4 Author: anibal-portero Date: Wed Aug 7 13:34:56 2013 +0200 Initial commit diff --git a/osgi.bundle.monitoring.dem2/.classpath b/osgi.bundle.monitoring.dem2/.classpath new file mode 100644 index 0000000..b1dabee --- /dev/null +++ b/osgi.bundle.monitoring.dem2/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/osgi.bundle.monitoring.dem2/.project b/osgi.bundle.monitoring.dem2/.project new file mode 100644 index 0000000..b5c925c --- /dev/null +++ b/osgi.bundle.monitoring.dem2/.project @@ -0,0 +1,28 @@ + + + osgi.bundle.monitoring.dem2 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/osgi.bundle.monitoring.dem2/.settings/org.eclipse.jdt.core.prefs b/osgi.bundle.monitoring.dem2/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..11f6e46 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/osgi.bundle.monitoring.dem2/.settings/org.eclipse.pde.core.prefs b/osgi.bundle.monitoring.dem2/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 0000000..d711c29 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +pluginProject.equinox=false +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/osgi.bundle.monitoring.dem2/META-INF/MANIFEST.MF b/osgi.bundle.monitoring.dem2/META-INF/MANIFEST.MF new file mode 100644 index 0000000..ee71479 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Dem2 +Bundle-SymbolicName: osgi.bundle.monitoring.dem2 +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: osgi.bundle.monitoring.dem2.Activator +Import-Package: org.osgi.framework;version="1.3.0", + osgi.framework.monitoring.event;version="1.0.0", + osgi.framework.monitoring.event.filter;version="1.0.0", + javax.swing, + javax.swing.table +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/Activator.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/Activator.java new file mode 100644 index 0000000..dc452af --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/Activator.java @@ -0,0 +1,55 @@ +package osgi.bundle.monitoring.dem2; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +import osgi.bundle.monitoring.dem2.controller.ButtonListener; +import osgi.bundle.monitoring.dem2.controller.CheckBoxMenuListener; +import osgi.bundle.monitoring.dem2.model.Model; +import osgi.bundle.monitoring.dem2.view.View; + +public class Activator implements BundleActivator +{ + + private static BundleContext context; + + private View view; + + static BundleContext getContext() + { + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext bundleContext) throws Exception + { + Activator.context = bundleContext; + + view = new View(); + view.initUi(); + + Model model = new Model(bundleContext); + + ButtonListener buttonListener = new ButtonListener(model, view); + CheckBoxMenuListener checkBoxMenuListener = new CheckBoxMenuListener(model); + + model.addObserver(view); + + view.completeUi(buttonListener, checkBoxMenuListener); + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception + { + Activator.context = null; + + view.close(); + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/controller/ButtonListener.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/controller/ButtonListener.java new file mode 100644 index 0000000..0bfca28 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/controller/ButtonListener.java @@ -0,0 +1,120 @@ +package osgi.bundle.monitoring.dem2.controller; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.JButton; + +import osgi.bundle.monitoring.dem2.model.Model; +import osgi.bundle.monitoring.dem2.view.View; + +public class ButtonListener implements MouseListener +{ + + private Model model; + + private View view; + + public ButtonListener(Model model, View view) + { + this.model = model; + this.view = view; + } + + @Override + public void mouseClicked(MouseEvent me) + { + String button = ((JButton)me.getSource()).getText(); + + if(button.compareTo("Install") == 0) + { + String fileName = view.installDialog(); + + if(fileName != null) + { + model.installBundle(fileName); + } + } + else if(button.compareTo("Uninstall") == 0) + { + long id = view.getSelectedBundleId(); + + if(id >= 0) + { + model.uninstallBundle(id); + } + } + else if(button.compareTo("Update") == 0) + { + long id = view.getSelectedBundleId(); + + if(id >= 0) + { + model.updateBundle(id); + } + } + else if(button.compareTo("Start") == 0) + { + long id = view.getSelectedBundleId(); + + if(id >= 0) + { + model.startBundle(id); + } + } + else if(button.compareTo("Stop") == 0) + { + long id = view.getSelectedBundleId(); + + if(id >= 0) + { + model.stopBundle(id); + } + } + else if(button.compareTo("Monitor") == 0) + { + long id = view.getSelectedBundleId(); + + if(id >= 0) + { + model.setIdOpened(id); + view.checkMonitoring(id); + } + } + else if(button.compareTo("Unmonitor") == 0) + { + long id = view.getSelectedBundleId(); + + if(id >= 0) + { + model.setIdClosed(id); + view.uncheckMonitoring(id); + } + } + } + + @Override + public void mouseEntered(MouseEvent me) + { + + } + + @Override + public void mouseExited(MouseEvent me) + { + + } + + @Override + public void mousePressed(MouseEvent me) + { + + } + + @Override + public void mouseReleased(MouseEvent me) + { + + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/controller/CheckBoxMenuListener.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/controller/CheckBoxMenuListener.java new file mode 100644 index 0000000..a573f75 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/controller/CheckBoxMenuListener.java @@ -0,0 +1,118 @@ +package osgi.bundle.monitoring.dem2.controller; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JCheckBoxMenuItem; + +import org.osgi.framework.BundleEvent; + +import osgi.bundle.monitoring.dem2.model.Model; +import osgi.framework.monitoring.event.ServiceEventMod; + +public class CheckBoxMenuListener implements ActionListener +{ + + private Model model; + + public CheckBoxMenuListener(Model model) + { + this.model = model; + } + + public void changeMonitorState(boolean state, int index) + { + if(state == true) + { + model.setMonitorOn(index); + } + else + { + model.setMonitorOff(index); + } + } + + private void changeTypeFilter(boolean state, int index, int type) + { + if(state == true) + { + model.setTypeOpened(index, type); + } + else + { + model.setTypeClosed(index, type); + } + } + + @Override + public void actionPerformed(ActionEvent ae) + { + JCheckBoxMenuItem cb = (JCheckBoxMenuItem)ae.getSource(); + String checkBox = cb.getText(); + + if(checkBox.compareTo("Bundle state") == 0) + { + changeMonitorState(cb.getState(), 0); + } + else if(checkBox.compareTo("Services") == 0) + { + changeMonitorState(cb.getState(), 1); + } + else if(checkBox.compareTo("Installed") == 0) + { + changeTypeFilter(cb.getState(), 0, BundleEvent.INSTALLED); + } + else if(checkBox.compareTo("Lazy Activation") == 0) + { + changeTypeFilter(cb.getState(), 0, BundleEvent.LAZY_ACTIVATION); + } + else if(checkBox.compareTo("Resolved") == 0) + { + changeTypeFilter(cb.getState(), 0, BundleEvent.RESOLVED); + } + else if(checkBox.compareTo("Started") == 0) + { + changeTypeFilter(cb.getState(), 0, BundleEvent.STARTED); + } + else if(checkBox.compareTo("Starting") == 0) + { + changeTypeFilter(cb.getState(), 0, BundleEvent.STARTING); + } + else if(checkBox.compareTo("Stopped") == 0) + { + changeTypeFilter(cb.getState(), 0, BundleEvent.STOPPED); + } + else if(checkBox.compareTo("Stopping") == 0) + { + changeTypeFilter(cb.getState(), 0, BundleEvent.STOPPING); + } + else if(checkBox.compareTo("Uninstalled") == 0) + { + changeTypeFilter(cb.getState(), 0, BundleEvent.UNINSTALLED); + } + else if(checkBox.compareTo("Unresolved") == 0) + { + changeTypeFilter(cb.getState(), 0, BundleEvent.UNRESOLVED); + } + else if(checkBox.compareTo("Updated") == 0) + { + changeTypeFilter(cb.getState(), 0, BundleEvent.UPDATED); + } + else if(checkBox.compareTo("Modified") == 0) + { + changeTypeFilter(cb.getState(), 1, ServiceEventMod.MODIFIED); + } + else if(checkBox.compareTo("Modified Endmatch") == 0) + { + changeTypeFilter(cb.getState(), 1, ServiceEventMod.MODIFIED_ENDMATCH); + } + else if(checkBox.compareTo("Registered") == 0) + { + changeTypeFilter(cb.getState(), 1, ServiceEventMod.REGISTERED); + } + else if(checkBox.compareTo("Unregistered") == 0) + { + changeTypeFilter(cb.getState(), 1, ServiceEventMod.UNREGISTERED); + } + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/model/ContextManager.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/model/ContextManager.java new file mode 100644 index 0000000..a65d961 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/model/ContextManager.java @@ -0,0 +1,75 @@ +package osgi.bundle.monitoring.dem2.model; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; + +/** + * Provides methods to manage bundles in the OSGi BundleContext + * @author Anibal + */ +public class ContextManager +{ + + private BundleContext bundleContext; + + public ContextManager(BundleContext bundleContext) + { + this.bundleContext = bundleContext; + } + + public void installBundle(String file) + { + try + { + bundleContext.installBundle("file:"+file); + } catch (BundleException e) + { + + } + } + + public void uninstallBundle(long id) + { + try + { + bundleContext.getBundle(id).uninstall(); + } catch (BundleException e) + { + + } + } + + public void updateBundle(long id) + { + try + { + bundleContext.getBundle(id).update(); + } catch (BundleException e) + { + + } + } + + public void startBundle(long id) + { + try + { + bundleContext.getBundle(id).start(); + } catch (BundleException e) + { + + } + } + + public void stopBundle(long id) + { + try + { + bundleContext.getBundle(id).stop(); + } catch (BundleException e) + { + + } + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/model/Model.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/model/Model.java new file mode 100644 index 0000000..05c3c4f --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/model/Model.java @@ -0,0 +1,84 @@ +package osgi.bundle.monitoring.dem2.model; + +import org.osgi.framework.BundleContext; +import osgi.bundle.monitoring.dem2.view.View; + +/** + * Provides an API with the actions the user can perform + * @author Anibal + */ +public class Model +{ + + private Monitor monitor; + + private ContextManager contextManager; + + public Model(BundleContext bundleContext) + { + monitor = new Monitor(bundleContext); + + contextManager = new ContextManager(bundleContext); + } + + public void installBundle(String fileName) + { + contextManager.installBundle(fileName); + } + + public void uninstallBundle(long id) + { + contextManager.uninstallBundle(id); + } + + public void updateBundle(long id) + { + contextManager.updateBundle(id); + } + + public void startBundle(long id) + { + contextManager.startBundle(id); + } + + public void stopBundle(long id) + { + contextManager.stopBundle(id); + } + + public void setIdOpened(long id) + { + monitor.setIdOpened(id); + } + + public void setIdClosed(long id) + { + monitor.setIdClosed(id); + } + + public void setMonitorOn(int index) + { + monitor.setMonitorOn(index); + } + + public void setMonitorOff(int index) + { + monitor.setMonitorOff(index); + } + + public void setTypeOpened(int index, int type) + { + monitor.setTypeOpened(index, type); + } + + public void setTypeClosed(int index, int type) + { + monitor.setTypeClosed(index, type); + } + + public void addObserver(View view) + { + monitor.addObserver(view); + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/model/Monitor.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/model/Monitor.java new file mode 100644 index 0000000..d4ae119 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/model/Monitor.java @@ -0,0 +1,143 @@ +package osgi.bundle.monitoring.dem2.model; + +import java.util.ArrayList; +import java.util.Observable; +import java.util.Observer; + +import org.osgi.framework.BundleContext; +import osgi.framework.monitoring.event.EventMonitor; +import osgi.framework.monitoring.event.ServiceRegistryMonitor; +import osgi.framework.monitoring.event.StateMonitor; +import osgi.framework.monitoring.event.filter.IdFilterSet; +import osgi.framework.monitoring.event.filter.TypeFilterSet; + +/** + * Manages the different types of monitors: state monitor and service monitor + * @author Anibal + */ +public class Monitor extends Observable implements Observer +{ + // Contains all monitor objects + private ArrayList bundleMonitors; + + // Contains all type filer for the various monitors + private ArrayList typeFilters; + + private IdFilterSet idFilter; + + /** + * Constructor. Initialize the different monitors + * @param bundleContext + */ + public Monitor(BundleContext bundleContext) + { + bundleMonitors = new ArrayList(); + + typeFilters = new ArrayList(); + + idFilter = new IdFilterSet(); + + // Positions in array 0: StateMonitor, 1: ServiceRegistryMonitor + bundleMonitors.add(new StateMonitor(bundleContext)); + bundleMonitors.add(new ServiceRegistryMonitor(bundleContext)); + + // Set the type filter sets to each monitor object + for(int i = 0; i < bundleMonitors.size() - 1; i++) + { + typeFilters.add(new TypeFilterSet()); + bundleMonitors.get(i).setTypeFilterSet(typeFilters.get(i)); + bundleMonitors.get(i).setBundleFilterSet(idFilter); + } + + // StateMonitor activated by default + setMonitorOn(0); + } + + /** + * Activate monitor object + * @param index 0: RepositoryMonitor, 1: StateMonitor, 2: ManifestMonitor, 3: DataFieldMonitor + */ + public void setMonitorOn(int index) + { + bundleMonitors.get(index).addObserver(this); + } + + /** + * Deactivate monitor object + * @param index 0: RepositoryMonitor, 1: StateMonitor, 2: ManifestMonitor, 3: DataFieldMonitor + */ + public void setMonitorOff(int index) + { + bundleMonitors.get(index).deleteObservers(); + } + + /** + * Open or close type in one TypeFilterSet + * @param typeFilterSet + * @param type type of event + * @param open true: opened, false: closed + */ + private void setType(TypeFilterSet typeFilterSet, int type, Boolean open) + { + typeFilterSet.addEntry(type, open); + } + + /** + * Open type in one TypeFilterSet + * @param index 0: RepositoryMonitor, 1: StateMonitor, 2: ManifestMonitor, 3: DataFieldMonitor + * @param type type of event + */ + public void setTypeOpened(int index, int type) + { + setType(typeFilters.get(index), type, true); + } + + /** + * Close type in one TypeFilterSet + * @param index 0: RepositoryMonitor, 1: StateMonitor, 2: ManifestMonitor, 3: DataFieldMonitor + * @param type type of event + */ + public void setTypeClosed(int index, int type) + { + setType(typeFilters.get(index), type, false); + } + + /** + * Open or close bundle in one IdFilterSet + * @param idBundle + * @param mode true: opened, false: closed + */ + private void setId(long idBundle, boolean mode) + { + idFilter.addEntry(idBundle, mode); + } + + /** + * Open bundle in one IdFilterSet + * @param idBundle + */ + public void setIdOpened(long idBundle) + { + setId(idBundle, true); + } + + /** + * Close bundle in one IdFilterSet + * @param idBundle + */ + public void setIdClosed(long idBundle) + { + setId(idBundle, false); + } + + /* (non-Javadoc) + * @see java.util.Observer#update(java.util.Observable, java.lang.Object) + */ + @Override + public void update(Observable obs, Object obj) + { + setChanged(); + notifyObservers(obj); + } + +} \ No newline at end of file diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/BundleTable.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/BundleTable.java new file mode 100644 index 0000000..8ff0232 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/BundleTable.java @@ -0,0 +1,137 @@ +package osgi.bundle.monitoring.dem2.view; + +import java.awt.Dimension; + +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleEvent; + + +public class BundleTable extends JScrollPane +{ + + private static final long serialVersionUID = 1L; + + JTable bundleTable; + + BundleTableModel tableModel; + + public BundleTable(int x, int y) + { + tableModel = new BundleTableModel(); + + bundleTable = new JTable(tableModel); + bundleTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + bundleTable.getColumnModel().getColumn(0).setPreferredWidth(75); + bundleTable.getColumnModel().getColumn(1).setPreferredWidth(75); + bundleTable.getColumnModel().getColumn(2).setPreferredWidth(150); + bundleTable.getColumnModel().getColumn(3).setPreferredWidth(300); + + setViewportView(bundleTable); + setPreferredSize(new Dimension(x, y)); + } + + private String getBundleState(int state) + { + switch(state) + { + case Bundle.UNINSTALLED: + return "Uninstalled"; + case Bundle.INSTALLED: + return "Installed"; + case Bundle.RESOLVED: + return "Resolved"; + case Bundle.STARTING: + return "Starting"; + case Bundle.STOPPING: + return "Stopping"; + case Bundle.ACTIVE: + return "Active"; + } + + return "Unknown"; + } + + private void addBundle(Bundle bundle) + { + tableModel.insertRow(true, + bundle.getBundleId(), + getBundleState(bundle.getState()), + bundle.getSymbolicName()); + } + + private void modifyBundle(Bundle bundle) + { + tableModel.modifyState(bundle.getBundleId(), + getBundleState(bundle.getState())); + } + + private void removeBundle(long id) + { + tableModel.deleteRow(id); + } + + public void changeBundle(BundleEvent be) + { + switch(be.getType()) + { + case BundleEvent.INSTALLED: + addBundle(be.getBundle()); + break; + case BundleEvent.LAZY_ACTIVATION: + modifyBundle(be.getBundle()); + break; + case BundleEvent.RESOLVED: + modifyBundle(be.getBundle()); + break; + case BundleEvent.STARTED: + modifyBundle(be.getBundle()); + break; + case BundleEvent.STARTING: + modifyBundle(be.getBundle()); + break; + case BundleEvent.STOPPED: + modifyBundle(be.getBundle()); + break; + case BundleEvent.STOPPING: + modifyBundle(be.getBundle()); + break; + case BundleEvent.UNINSTALLED: + removeBundle(be.getBundle().getBundleId()); + break; + case BundleEvent.UNRESOLVED: + modifyBundle(be.getBundle()); + break; + case BundleEvent.UPDATED: + modifyBundle(be.getBundle()); + break; + } + } + + public long getSelectedBundleId() + { + int index = bundleTable.getSelectedRow(); + + if(index >= 0) + { + return tableModel.idOfRow(index); + } + + return -1; + } + + public void checkMonitor(long id) + { + tableModel.modifyMonitoring(id, true); + } + + public void uncheckMonitor(long id) + { + tableModel.modifyMonitoring(id, false); + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/BundleTableModel.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/BundleTableModel.java new file mode 100644 index 0000000..e2fd78f --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/BundleTableModel.java @@ -0,0 +1,143 @@ +package osgi.bundle.monitoring.dem2.view; + +import java.util.ArrayList; + +import javax.swing.table.AbstractTableModel; + +public class BundleTableModel extends AbstractTableModel +{ + + private static final long serialVersionUID = 1L; + + private String[] columnNames = + {"Monitoring", + "Id", + "State", + "Symbolic Name" + }; + + private ArrayList> data; + + public BundleTableModel() + { + data = new ArrayList>(); + } + + @Override + public int getColumnCount() + { + return columnNames.length; + } + + @Override + public int getRowCount() + { + return data.size(); + } + + public String getColumnName(int col) + { + return columnNames[col]; + } + + @Override + public Object getValueAt(int row, int col) + { + return data.get(row).get(col); + } + + public Class getColumnClass(int col) + { + return getValueAt(0, col).getClass(); + } + + public void setValueAt(Object value, int row, int col) + { + if(row == data.size()) + { + data.add(new ArrayList()); + data.get(row).add(value); + data.get(row).add(null); + data.get(row).add(null); + data.get(row).add(null); + fireTableDataChanged(); + } + else if(row < data.size()) + { + data.get(row).set(col, value); + fireTableCellUpdated(row, col); + } + } + + public void insertRow(Boolean monitoring, long id, String state, String name) + { + int row = data.size(); + + setValueAt(monitoring, row, 0); + setValueAt(id, row, 1); + setValueAt(state, row, 2); + setValueAt(name, row, 3); + } + + private int rowOfId(long id) + { + int first = 0; + int last = data.size() - 1; + + int middle; + + while((first <= last)) + { + middle = (int)(first + ((last - first)/2)); + + if(id < (long)data.get(middle).get(1)) + { + last = middle - 1; + } + else if(id > (long)data.get(middle).get(1)) + { + first = middle + 1; + } + else + { + return middle; + } + } + + return -1; + } + + public void modifyState(long id, String state) + { + int row = rowOfId(id); + + if(row > -1) + { + setValueAt(state, row, 2); + } + } + + public void modifyMonitoring(long id, Boolean monitoring) + { + int row = rowOfId(id); + + if(row > -1) + { + setValueAt(monitoring, row, 0); + } + } + + public void deleteRow(long id) + { + int row = rowOfId(id); + + data.remove(row); + fireTableDataChanged(); + } + + public long idOfRow(int row) + { + return (long)data.get(row).get(1); + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/LeftPane.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/LeftPane.java new file mode 100644 index 0000000..b41681b --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/LeftPane.java @@ -0,0 +1,104 @@ +package osgi.bundle.monitoring.dem2.view; + +import java.awt.Container; +import java.awt.Dimension; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JLabel; + +import org.osgi.framework.BundleEvent; + +import osgi.framework.monitoring.event.ServiceEventMod; + +public class LeftPane extends Container +{ + + private static final long serialVersionUID = 1L; + + private LogList logList; + + private BundleTable bundleTable; + + private ServiceTable serviceTable; + + public LeftPane() + { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + addFillerToYPane(); + addLabelToPane("Installed bundles"); + addBundleListToPane(600, 150); + addFillerToYPane(); + addLabelToPane("Services advailable"); + addServiceListToPane(600, 150); + addFillerToYPane(); + addLabelToPane("Monitoring log"); + addLogListToPane(600, 200); + addFillerToYPane(); + } + + private void addFillerToYPane() + { + add(Box.createRigidArea(new Dimension(0, 25))); + } + + private void addLabelToPane(String text) + { + JLabel label = new JLabel(text); + add(label); + } + + private void addLogListToPane(int x, int y) + { + logList = new LogList(x, y); + + add(logList); + } + + private void addServiceListToPane(int x, int y) + { + serviceTable = new ServiceTable(x, y); + + add(serviceTable); + } + + private void addBundleListToPane(int x, int y) + { + bundleTable = new BundleTable(x, y); + + add(bundleTable); + } + + public void checkEvent(Object event) + { + String className = event.getClass().getName(); + + if(className.compareTo(BundleEvent.class.getName()) == 0) + { + bundleTable.changeBundle((BundleEvent)event); + logList.logBundleEvent((BundleEvent)event); + } + else if(className.compareTo(ServiceEventMod.class.getName()) == 0) + { + serviceTable.changeService((ServiceEventMod)event); + logList.logServiceEvent((ServiceEventMod)event); + } + } + + public long getSelectedBundleId() + { + return bundleTable.getSelectedBundleId(); + } + + public void checkMonitor(long id) + { + bundleTable.checkMonitor(id); + } + + public void uncheckMonitor(long id) + { + bundleTable.uncheckMonitor(id); + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/LogList.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/LogList.java new file mode 100644 index 0000000..c739c80 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/LogList.java @@ -0,0 +1,134 @@ +package osgi.bundle.monitoring.dem2.view; + +import java.awt.Dimension; + +import javax.swing.DefaultListModel; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.ListSelectionModel; + +import org.osgi.framework.BundleEvent; +import org.osgi.framework.ServiceEvent; + +import osgi.framework.monitoring.event.ServiceEventMod; + +public class LogList extends JScrollPane +{ + + private static final long serialVersionUID = 1L; + + private JList listLog; + + private DefaultListModel listModelLog; + + public LogList(int x, int y) + { + listLog = new JList(); + + listModelLog = new DefaultListModel(); + + listLog.setModel(listModelLog); + + setViewportView(listLog); + setPreferredSize(new Dimension(x, y)); + + listLog.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + } + + public void insertList(String message) + { + listModelLog.addElement(message); + } + + public void insertListLog(String message) + { + try + { + Thread.sleep(10); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + + insertList(message); + } + + private String getBundleEvent(int type) + { + switch(type) + { + case BundleEvent.INSTALLED: + return "Installed"; + case BundleEvent.LAZY_ACTIVATION: + return "Lazily activated"; + case BundleEvent.RESOLVED: + return "Resolved"; + case BundleEvent.STARTED: + return "Started"; + case BundleEvent.STARTING: + return "Activated"; + case BundleEvent.STOPPED: + return "Stopped"; + case BundleEvent.STOPPING: + return "Deactivated"; + case BundleEvent.UNINSTALLED: + return "Uninstalled"; + case BundleEvent.UNRESOLVED: + return "Unresolved"; + case BundleEvent.UPDATED: + return "Updated"; + } + + return "Unknown"; + } + + private String getServiceEvent(int type) + { + switch(type) + { + case ServiceEvent.MODIFIED: + return "modified"; + case ServiceEvent.MODIFIED_ENDMATCH: + return "modified endmatch"; + case ServiceEvent.REGISTERED: + return "registered"; + case ServiceEvent.UNREGISTERING: + return "unregistered"; + } + + return "Unknown"; + } + + public void logBundleEvent(BundleEvent be) + { + String message = "Bundle state: bundle "+ + be.getBundle().getBundleId()+ + " "+ + getBundleEvent(be.getType()); + insertListLog(message); + } + + public void logServiceEvent(ServiceEventMod se) + { + String message = "Service registry: bundle "+ + se.getServiceReference().getBundle().getBundleId()+ + " has "+ + getServiceEvent(se.getType())+ + " a service "+ + se.getService().getClass().getName(); + + //Only working with this + /*try + { + Thread.sleep(10); + } + catch (InterruptedException e) + { + e.printStackTrace(); + }*/ + + insertListLog(message); + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/Menu.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/Menu.java new file mode 100644 index 0000000..d63e4a0 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/Menu.java @@ -0,0 +1,102 @@ +package osgi.bundle.monitoring.dem2.view; + +import java.util.ArrayList; + +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import osgi.bundle.monitoring.dem2.controller.CheckBoxMenuListener; + + +public class Menu extends JMenuBar +{ + + private static final long serialVersionUID = 1L; + + private ArrayList checkBoxesMonitor; + + private ArrayList checkBoxesStatFilter; + + private ArrayList checkBoxesServFilter; + + public Menu() + { + checkBoxesMonitor = new ArrayList(); + + checkBoxesStatFilter = new ArrayList(); + + checkBoxesServFilter = new ArrayList(); + + JMenu monitorMenu, filterMenu, statSubMenu, servSubMenu; + + monitorMenu = new JMenu("Monitors"); + + checkBoxesMonitor.add(new JCheckBoxMenuItem("Bundle state")); + checkBoxesMonitor.add(new JCheckBoxMenuItem("Services")); + + for(JCheckBoxMenuItem checkBox: checkBoxesMonitor) + { + monitorMenu.add(checkBox); + } + + checkBoxesMonitor.get(0).setState(true); + + filterMenu = new JMenu("Filters"); + + statSubMenu = new JMenu("Bundle state"); + servSubMenu = new JMenu("Services"); + + checkBoxesStatFilter.add(new JCheckBoxMenuItem("Installed")); + checkBoxesStatFilter.add(new JCheckBoxMenuItem("Lazy Activation")); + checkBoxesStatFilter.add(new JCheckBoxMenuItem("Resolved")); + checkBoxesStatFilter.add(new JCheckBoxMenuItem("Started")); + checkBoxesStatFilter.add(new JCheckBoxMenuItem("Starting")); + checkBoxesStatFilter.add(new JCheckBoxMenuItem("Stopped")); + checkBoxesStatFilter.add(new JCheckBoxMenuItem("Stopping")); + checkBoxesStatFilter.add(new JCheckBoxMenuItem("Uninstalled")); + checkBoxesStatFilter.add(new JCheckBoxMenuItem("Unresolved")); + checkBoxesStatFilter.add(new JCheckBoxMenuItem("Updated")); + + for(JCheckBoxMenuItem checkBox: checkBoxesStatFilter) + { + statSubMenu.add(checkBox); + checkBox.setState(true); + } + + checkBoxesServFilter.add(new JCheckBoxMenuItem("Modified")); + checkBoxesServFilter.add(new JCheckBoxMenuItem("Modified Endmatch")); + checkBoxesServFilter.add(new JCheckBoxMenuItem("Registered")); + checkBoxesServFilter.add(new JCheckBoxMenuItem("Unregistered")); + + for(JCheckBoxMenuItem checkBox: checkBoxesServFilter) + { + servSubMenu.add(checkBox); + checkBox.setState(true); + } + + filterMenu.add(statSubMenu); + filterMenu.add(servSubMenu); + + add(monitorMenu); + add(filterMenu); + } + + public void completeMenu(CheckBoxMenuListener checkBoxMenuListener) + { + for(JCheckBoxMenuItem checkBox: checkBoxesMonitor) + { + checkBox.addActionListener(checkBoxMenuListener); + } + + for(JCheckBoxMenuItem checkBox: checkBoxesStatFilter) + { + checkBox.addActionListener(checkBoxMenuListener); + } + + for(JCheckBoxMenuItem checkBox: checkBoxesServFilter) + { + checkBox.addActionListener(checkBoxMenuListener); + } + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/RightPane.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/RightPane.java new file mode 100644 index 0000000..e8c4cd5 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/RightPane.java @@ -0,0 +1,64 @@ +package osgi.bundle.monitoring.dem2.view; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.util.ArrayList; + +import javax.swing.Box; +import javax.swing.JButton; + +import osgi.bundle.monitoring.dem2.controller.ButtonListener; + + +public class RightPane extends Container +{ + + private static final long serialVersionUID = 1L; + + private ArrayList buttons; + + public RightPane() + { + setLayout(new GridLayout(15, 1)); + + buttons = new ArrayList(); + + addFillerToYPane(); + addButtonToPane("Install"); + addFillerToYPane(); + addButtonToPane("Uninstall"); + addFillerToYPane(); + addButtonToPane("Update"); + addFillerToYPane(); + addButtonToPane("Start"); + addFillerToYPane(); + addButtonToPane("Stop"); + addFillerToYPane(); + addButtonToPane("Monitor"); + addFillerToYPane(); + addButtonToPane("Unmonitor"); + addFillerToYPane(); + } + + private void addFillerToYPane() + { + add(Box.createRigidArea(new Dimension(0, 25))); + } + + private void addButtonToPane(String text) + { + JButton button = new JButton(text); + buttons.add(button); + add(button); + } + + public void completeRightPane(ButtonListener buttonListener) + { + for(JButton button: buttons) + { + button.addMouseListener(buttonListener); + } + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/ServiceTable.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/ServiceTable.java new file mode 100644 index 0000000..bc6d20f --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/ServiceTable.java @@ -0,0 +1,80 @@ +package osgi.bundle.monitoring.dem2.view; + +import java.awt.Dimension; + +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; + +import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceReference; + +import osgi.framework.monitoring.event.ServiceEventMod; + +public class ServiceTable extends JScrollPane +{ + + private static final long serialVersionUID = 1L; + + JTable serviceTable; + + private ServiceTableModel tableModel; + + public ServiceTable(int x, int y) + { + tableModel = new ServiceTableModel(); + + serviceTable = new JTable(tableModel); + serviceTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + serviceTable.getColumnModel().getColumn(0).setPreferredWidth(225); + serviceTable.getColumnModel().getColumn(1).setPreferredWidth(75); + serviceTable.getColumnModel().getColumn(2).setPreferredWidth(200); + serviceTable.getColumnModel().getColumn(3).setPreferredWidth(100); + + setViewportView(serviceTable); + setPreferredSize(new Dimension(x, y)); + } + + private void addService(ServiceReference reference, String serviceName) + { + tableModel.insertRow(reference, + serviceName, + reference.getBundle().getBundleId(), + reference.getBundle().getSymbolicName(), + reference.getBundle().getVersion().toString()); + } + + private void modifyService(ServiceReference reference, String serviceName) + { + tableModel.modifyState(reference, + serviceName, + reference.getBundle().getBundleId(), + reference.getBundle().getSymbolicName(), + reference.getBundle().getVersion().toString()); + } + + private void removeService(ServiceReference reference) + { + tableModel.deleteRow(reference); + } + + public void changeService(ServiceEventMod se) + { + switch(se.getType()) + { + case ServiceEvent.MODIFIED: + modifyService(se.getServiceReference(), se.getService().getClass().getName()); + break; + case ServiceEvent.MODIFIED_ENDMATCH: + modifyService(se.getServiceReference(), se.getService().getClass().getName()); + break; + case ServiceEvent.REGISTERED: + addService(se.getServiceReference(), se.getService().getClass().getName()); + break; + case ServiceEvent.UNREGISTERING: + removeService(se.getServiceReference()); + break; + } + } +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/ServiceTableModel.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/ServiceTableModel.java new file mode 100644 index 0000000..ec132c5 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/ServiceTableModel.java @@ -0,0 +1,130 @@ +package osgi.bundle.monitoring.dem2.view; + +import java.util.ArrayList; + +import javax.swing.table.AbstractTableModel; + +import org.osgi.framework.ServiceReference; + +public class ServiceTableModel extends AbstractTableModel +{ + + private static final long serialVersionUID = 1L; + + private String[] columnNames = + {"Service Name", + "Bundle Id", + "Bundle Symbolic Name", + "Bundle Version" + }; + + private ArrayList> data; + + private ArrayList> indexServiceList; + + public ServiceTableModel() + { + data = new ArrayList>(); + + indexServiceList = new ArrayList>(); + } + + @Override + public int getColumnCount() + { + return columnNames.length; + } + + @Override + public int getRowCount() + { + return data.size(); + } + + public String getColumnName(int col) + { + return columnNames[col]; + } + + @Override + public Object getValueAt(int row, int col) + { + return data.get(row).get(col); + } + + public Class getColumnClass(int col) + { + return getValueAt(0, col).getClass(); + } + + public void setValueAt(Object value, int row, int col) + { + if(row == data.size()) + { + data.add(new ArrayList()); + data.get(row).add(value); + data.get(row).add(null); + data.get(row).add(null); + data.get(row).add(null); + fireTableDataChanged(); + } + else if(row < data.size()) + { + data.get(row).set(col, value); + fireTableCellUpdated(row, col); + } + } + + public void insertRow(ServiceReference reference, String serviceName, + long bundleId, String symbolicName, String string) + { + int row = data.size(); + + setValueAt(serviceName, row, 0); + setValueAt(bundleId, row, 1); + setValueAt(symbolicName, row, 2); + setValueAt(string, row, 3); + + indexServiceList.add(reference); + } + + public void modifyState(ServiceReference reference, String serviceName, + long bundleId, String symbolicName, String string) + { + int row = indexOfServiceList(reference); + + if(row > -1) + { + setValueAt(serviceName, row, 0); + setValueAt(bundleId, row, 1); + setValueAt(symbolicName, row, 2); + setValueAt(string, row, 3); + } + } + + public void deleteRow(ServiceReference reference) + { + int row = indexOfServiceList(reference); + + data.remove(row); + fireTableDataChanged(); + + indexServiceList.remove(row); + } + + private int indexOfServiceList(ServiceReference unregistered) + { + int index = -1; + + for(ServiceReference item: indexServiceList) + { + if(unregistered.equals(item) == true) + { + index = indexServiceList.indexOf(item); + } + } + + return index; + } + +} diff --git a/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/View.java b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/View.java new file mode 100644 index 0000000..6aa4629 --- /dev/null +++ b/osgi.bundle.monitoring.dem2/src/osgi/bundle/monitoring/dem2/view/View.java @@ -0,0 +1,111 @@ +package osgi.bundle.monitoring.dem2.view; + +import java.awt.Container; +import java.awt.Dimension; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import osgi.bundle.monitoring.dem2.controller.ButtonListener; +import osgi.bundle.monitoring.dem2.controller.CheckBoxMenuListener; + + +public class View implements Observer +{ + + private JFrame mainFrame; + + private LeftPane leftPane; + + private RightPane rightPane; + + private Menu menu; + + public View() + { + rightPane = new RightPane(); + + leftPane = new LeftPane(); + + menu = new Menu(); + } + + private static void addFillerToXPane(Container pane) + { + pane.add(Box.createRigidArea(new Dimension(25, 0))); + } + + private void addComponentsToPane(Container pane) + { + pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS)); + + addFillerToXPane(pane); + pane.add(leftPane); + addFillerToXPane(pane); + pane.add(rightPane); + addFillerToXPane(pane); + } + + public void initUi() + { + mainFrame = new JFrame("Monitoring System: demonstrator 2"); + + mainFrame.setJMenuBar(menu); + addComponentsToPane(mainFrame.getContentPane()); + + mainFrame.pack(); + mainFrame.setResizable(false); + mainFrame.setVisible(true); + } + + public String installDialog() + { + JFileChooser fc = new JFileChooser(); + + int returnVal = fc.showOpenDialog(mainFrame); + + if(returnVal == JFileChooser.APPROVE_OPTION) + { + return fc.getSelectedFile().getName(); + } + + return null; + } + + public void completeUi(ButtonListener buttonListener, CheckBoxMenuListener checkBoxMenuListener) + { + rightPane.completeRightPane(buttonListener); + + menu.completeMenu(checkBoxMenuListener); + } + + public long getSelectedBundleId() + { + return leftPane.getSelectedBundleId(); + } + + public void checkMonitoring(long id) + { + leftPane.checkMonitor(id); + } + + public void uncheckMonitoring(long id) + { + leftPane.uncheckMonitor(id); + } + + public void close() + { + mainFrame.setVisible(false); + mainFrame.dispose(); + } + + @Override + public void update(Observable obs, Object obj) + { + leftPane.checkEvent(obj); + } +} diff --git a/osgi.framework.monitoring/.classpath b/osgi.framework.monitoring/.classpath new file mode 100644 index 0000000..b1dabee --- /dev/null +++ b/osgi.framework.monitoring/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/osgi.framework.monitoring/.project b/osgi.framework.monitoring/.project new file mode 100644 index 0000000..aa398f0 --- /dev/null +++ b/osgi.framework.monitoring/.project @@ -0,0 +1,28 @@ + + + osgi.framework.monitoring + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/osgi.framework.monitoring/.settings/org.eclipse.jdt.core.prefs b/osgi.framework.monitoring/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..11f6e46 --- /dev/null +++ b/osgi.framework.monitoring/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/osgi.framework.monitoring/.settings/org.eclipse.pde.core.prefs b/osgi.framework.monitoring/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 0000000..d711c29 --- /dev/null +++ b/osgi.framework.monitoring/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +pluginProject.equinox=false +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/osgi.framework.monitoring/META-INF/MANIFEST.MF b/osgi.framework.monitoring/META-INF/MANIFEST.MF new file mode 100644 index 0000000..79ad934 --- /dev/null +++ b/osgi.framework.monitoring/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Monitoring +Bundle-SymbolicName: osgi.framework.monitoring +Bundle-Version: 1.0.0.qualifier +Import-Package: org.osgi.framework;version="1.3.0", + org.osgi.framework.hooks.weaving;version="1.0.0", + javassist, + javassist.expr +Export-Package: osgi.framework.monitoring.event;version="1.0.0", + osgi.framework.monitoring.event.filter;version="1.0.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/DataFieldEvent.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/DataFieldEvent.java new file mode 100644 index 0000000..4fe9bb6 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/DataFieldEvent.java @@ -0,0 +1,68 @@ +package osgi.framework.monitoring.event; + +import java.util.EventObject; + +/** + * Contains the relevant data of a DataFieldMonitor event + * @author Anibal + */ +public class DataFieldEvent extends EventObject +{ + + private static final long serialVersionUID = 1L; + + // New field value + private Object field; + + // Monitored field's class name + private String className; + + // Monitored field's name + private String fieldName; + + /** + * Constructor + * @param obs observable that raised the event + * @param field monitored field object + * @param className monitored field's class name + * @param fieldName monitored field name + */ + public DataFieldEvent(Object obs, + Object field, + String className, + String fieldName) + { + super(obs); + + this.field = field; + + this.className = className; + + this.fieldName = fieldName; + } + + /** + * @return new value of field + */ + public Object getField() + { + return field; + } + + /** + * @return monitored field's class name + */ + public String getClassName() + { + return className; + } + + /** + * @return monitored field name + */ + public String getFieldName() + { + return fieldName; + } + +} \ No newline at end of file diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/DataFieldMonitor.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/DataFieldMonitor.java new file mode 100644 index 0000000..7520158 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/DataFieldMonitor.java @@ -0,0 +1,124 @@ +package osgi.framework.monitoring.event; + +import java.util.ArrayList; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.osgi.framework.hooks.weaving.WeavingHook; + +import osgi.framework.monitoring.event.impl.ClassWeaver; +import osgi.framework.monitoring.event.impl.MonitoredField; + + +/** + * Will monitor different class attributes within a bundle and will raise an + * event if any previously specified primitive data field is modified + * @author Anibal + */ +public class DataFieldMonitor extends EventMonitor +{ + + // Contains OSGi ServiceRegistration for DataFieldMonitor necessary + // services + private ArrayList> serviceRegistration; + + // Contains information about monitored field and its classes + private ArrayList fields; + + /** + * Constructor + * @param bundleContext - OSGi BundleContext object + */ + public DataFieldMonitor(BundleContext bundleContext) + { + super(bundleContext); + + serviceRegistration = new ArrayList>(); + + fields = new ArrayList(); + } + + /** + * It will specify a new class and field to be monitored + * @param className + * @param fieldName + * @return true if the specified data field exists + */ + public boolean addDataField(String className, String fieldName) + { + if(getIndex(className, fieldName) == -1) + { + fields.add(new MonitoredField(className, fieldName)); + return true; + } + + return false; + } + + /** + * @param className + * @param fieldName + * @return position of field in the array + */ + private int getIndex(String className, String fieldName) + { + for(int i = 0; i < fields.size(); i++) + { + if(className.compareTo(fields.get(i).getClassName()) == 0) + { + if(fieldName.compareTo(fields.get(i).getFieldName()) == 0) + { + return i; + } + } + } + + return -1; + } + + /** + * Registers the necessary services for data field monitor to work. + * Initialize monitoring process + */ + public void registerWeavingService() + { + // DataFieldUpdate will provide an interface that can be used to raise + // a DataFieldMonitor event + serviceRegistration.add(super.getBundleContext().registerService( + DataFieldUpdate.class.getName(), + new DataFieldUpdate(this), null)); + // WeavingHook will allow class modifications to insert invocations to + // DataFieldUpdate methods + serviceRegistration.add(super.getBundleContext().registerService( + WeavingHook.class.getName(), + new ClassWeaver(fields), + null)); + } + + /** + * Unregister the necessary services for data field monitor to work + */ + public void unregisterWeavingService() + { + for(ServiceRegistration sr: serviceRegistration) + { + if(sr != null) + { + sr.unregister(); + } + } + + serviceRegistration.clear(); + } + + /** + * Used to create and raise an event + * @param field + * @param className + * @param fieldName + */ + public void update(Object field, String className, String fieldName) + { + super.notify(new DataFieldEvent(this, field, className, fieldName)); + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/DataFieldUpdate.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/DataFieldUpdate.java new file mode 100644 index 0000000..4725897 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/DataFieldUpdate.java @@ -0,0 +1,65 @@ +package osgi.framework.monitoring.event; + +/** + * This class is registered as a service by DataFieldMonitor, inserted in a + * weave class by ClassWeaver and invoked by that class when a field value + * is modified. It contains the different update functions for the different + * primitive data types + * @author Anibal + */ +public class DataFieldUpdate +{ + + private DataFieldMonitor dfm; + + public DataFieldUpdate(DataFieldMonitor dfm) + { + this.dfm = dfm; + } + + public void update(Object field, String className, String fieldName) + { + dfm.update(field, className, fieldName); + } + + public void update(byte field, String className, String fieldName) + { + dfm.update((Byte)field, className, fieldName); + } + + public void update(short field, String className, String fieldName) + { + dfm.update((Short)field, className, fieldName); + } + + public void update(int field, String className, String fieldName) + { + dfm.update((Integer)field, className, fieldName); + } + + public void update(long field, String className, String fieldName) + { + dfm.update((Long)field, className, fieldName); + } + + public void update(float field, String className, String fieldName) + { + dfm.update((Float)field, className, fieldName); + } + + public void update(double field, String className, String fieldName) + { + dfm.update((Double)field, className, fieldName); + } + + public void update(boolean field, String className, String fieldName) + { + dfm.update((Boolean)field, className, fieldName); + } + + public void update(char field, String className, String fieldName) + { + dfm.update((Character)field, className, fieldName); + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/EventMonitor.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/EventMonitor.java new file mode 100644 index 0000000..4888b2f --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/EventMonitor.java @@ -0,0 +1,136 @@ +package osgi.framework.monitoring.event; + + +import java.util.EventObject; +import java.util.Observable; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; + +import osgi.framework.monitoring.event.filter.BundleFilterSet; +import osgi.framework.monitoring.event.filter.IdFilterSet; +import osgi.framework.monitoring.event.filter.NameFilterSet; +import osgi.framework.monitoring.event.filter.TypeFilterSet; + + + +/** + * Abstract class that can be extended to create event based monitor classes. + * It supports type filter set and bundle filter set + * @author Anibal + */ +public abstract class EventMonitor extends Observable +{ + //OSGi BundleContext + BundleContext bundleContext = null; + + TypeFilterSet typeFilterSet = null; + + BundleFilterSet bundleFilterSet = null; + + /** + * Constructor + * @param bundleContext OSGi bundle context + */ + public EventMonitor(BundleContext bundleContext) + { + this.bundleContext = bundleContext; + } + + /** + * Set a new TypeFilterSet that will control the event flow depending on + * the event type + * @param fs + */ + public void setTypeFilterSet(TypeFilterSet fs) + { + typeFilterSet = fs; + } + + /** + * Get TypeFilterSet + * @return null if not previously set + */ + public TypeFilterSet getFilterSet() + { + return typeFilterSet; + } + + /** + * Set a new BundleFilterSet that will control the event flow depending on + * the bundle that raises the event + * @param fs + */ + public void setBundleFilterSet(BundleFilterSet fs) + { + bundleFilterSet = fs; + } + + /** + * Get BundleFilterSet + * @return null if not previously set + */ + public BundleFilterSet getBundleFilterSet() + { + return bundleFilterSet; + } + + /** + * @return OSGi BundleContext + */ + public BundleContext getBundleContext() + { + return bundleContext; + } + + /** + * Notify the observers, invoked by the child monitor class itself + * @param eo the event generated + */ + public void notify(EventObject eo) + { + setChanged(); + notifyObservers(eo); + } + + /** + * Notify the observers after checking filters, invoked by the monitors + * that support them + * @param eo + * @param type type code of event + * @param bundle bundle that raised the event + */ + public void checkUpdate(EventObject eo, int type, Bundle bundle) + { + Boolean notify = true; + + // Check if the event meets the TypeFilterSet specifications + if(typeFilterSet != null) + { + notify = ((TypeFilterSet)typeFilterSet).isOpen(type); + } + + // Check if the bundle meets the BundleFilterSet specifications + if((notify != false) && (bundleFilterSet != null)) + { + String filterClassName = bundleFilterSet.getClass().getName(); + + // Check by name + if(filterClassName.compareTo(NameFilterSet.class.getName()) == 0) + { + notify = ((NameFilterSet)bundleFilterSet).isOpen(bundle.getSymbolicName()); + } + // Check by id + else if(filterClassName.compareTo(IdFilterSet.class.getName()) == 0) + { + notify = ((IdFilterSet)bundleFilterSet).isOpen(bundle.getBundleId()); + } + } + + if(notify) + { + notify(eo); + } + + } +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ManifestEvent.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ManifestEvent.java new file mode 100644 index 0000000..7deed70 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ManifestEvent.java @@ -0,0 +1,74 @@ +package osgi.framework.monitoring.event; + +import java.util.EventObject; + +import org.osgi.framework.Bundle; + +/** + * Contains the relevant data of a ManifestMonitor event + * @author Anibal + */ +public class ManifestEvent extends EventObject +{ + // CONSTANTS + public static final int CREATED = 1; + + public static final int MODIFIED = 2; + + public static final int DELETED = 3; + + private static final long serialVersionUID = 1L; + + // Bundle that raised the event + private Bundle bundle; + + // Header that was created, modified or deleted + private String header; + + // Type of event 1: CREATED, 2: MODIFIED or 3: DELETED + private int type; + + /** + * Constructor + * @param source observable that raised the event + * @param bundle bundle that raised the event + * @param header header that was created, modified or deleted + * @param type 1: CREATED, 2: MODIFIED or 3: DELETED + */ + public ManifestEvent(Object source, + Bundle bundle, + String header, + int type) + { + super(source); + + this.bundle = bundle; + this.header = header; + this.type = type; + } + + /** + * @return bundle that raised the event + */ + public Bundle getBundle() + { + return bundle; + } + + /** + * @return header that was created, modified or deleted + */ + public String getHeader() + { + return header; + } + + /** + * @return 1: CREATED, 2: MODIFIED or 3: DELETED + */ + public int getType() + { + return type; + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ManifestMonitor.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ManifestMonitor.java new file mode 100644 index 0000000..d961d40 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ManifestMonitor.java @@ -0,0 +1,242 @@ +package osgi.framework.monitoring.event; + +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import java.util.Observable; +import java.util.Observer; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; + +import osgi.framework.monitoring.event.filter.TypeFilterSet; + +/** + * Will monitor the installed bundles manifest and will raise an event if any + * entry of the manifest of any updated bundle is created, modified or deleted + * @author Anibal + */ +public class ManifestMonitor extends EventMonitor implements Observer +{ + // Stores a map with bundle id and its correspondent manifest copies + Map> manifestMap; + + /** + * Constructor. Initialize monitoring process + * @param bundleContext OSGi BundleContext + */ + public ManifestMonitor(BundleContext bundleContext) + { + super(bundleContext); + + initManifestMap(); + initObserver(); + } + + /** + * This method adds the current bundles and manifest copies to the map + */ + private void initManifestMap() + { + manifestMap = new HashMap>(); + + Bundle[] bundles = super.getBundleContext().getBundles(); + + for(int i = 0; i < bundles.length; i++) + { + addManifestToMap(bundles[i]); + } + } + + /** + * This method adds a new bundle and its manifest copy to the map + * @param bundle + */ + private void addManifestToMap(Bundle bundle) + { + manifestMap.put(bundle.getBundleId(), + cloneDictionary(bundle.getHeaders())); + } + + /** + * This method get a manifest and make a copy of it + * @param headers manifest + * @return copy of the manifest + */ + private Dictionary cloneDictionary( + Dictionary headers) + { + Enumeration keys = headers.keys(); + Dictionary copy = new Hashtable(); + String header; + + while(keys.hasMoreElements()) + { + header = keys.nextElement(); + copy.put(header, headers.get(header)); + } + + return copy; + } + + /** + * This method removes a bundle and manifest copy from the map + * @param bundle + */ + private void removeManifestFromMap(Bundle bundle) + { + manifestMap.remove(bundle.getBundleId()); + } + + /** + * This method initialize the bundle state monitor + */ + private void initObserver() + { + StateMonitor bsm = new StateMonitor(super.getBundleContext()); + + bsm.addObserver(this); + } + + /** + * Initialize the TypeFilterSet values with ManifestMonitor ones + * @param tf + */ + public void typeFilterSetDefaultConfiguration(TypeFilterSet tf) + { + if(tf.size() > 0) + { + tf.clear(); + } + + tf.addEntry(ManifestEvent.CREATED, false); + tf.addEntry(ManifestEvent.MODIFIED, false); + tf.addEntry(ManifestEvent.DELETED, false); + } + + /* (non-Javadoc) + * @see java.util.Observer#update(java.util.Observable, java.lang.Object) + */ + @Override + public void update(Observable obs, Object obj) + { + int type = ((BundleEvent)obj).getType(); + Bundle bundle = ((BundleEvent)obj).getBundle(); + + // ManifestMonitor uses StateMonitor, and will make different changes + // in its map if there is a change in the state of any bundle. This is + // made to keep updated information about installed bundles and its + // manifest files + switch(type) + { + case BundleEvent.INSTALLED: + addManifestToMap(bundle); + break; + case BundleEvent.UPDATED: + checkManifestChanges(bundle); + break; + case BundleEvent.UNINSTALLED: + removeManifestFromMap(bundle); + break; + } + } + + /** + * This method raises a ManifestMonitor event + * @param bundle bundle taht raised the event + * @param header header that was created, modified or deleted + * @param type 1: CREATED, 2: MODIFIED or 3: DELETED + */ + private void raiseEvent(Bundle bundle, String header, int type) + { + ManifestEvent me = new ManifestEvent(this, bundle, header, type); + + super.checkUpdate(me, type, bundle); + } + + /** + * This method compares a current bundle manifest with its old version to + * seek for created and modified headers + * @param bundle + * @param oldManifest + * @return + */ + private int compareHeaders(Bundle bundle, + Dictionary oldManifest) + { + int created = 0; + Dictionary newManifest = bundle.getHeaders(); + String header; + Enumeration keys = newManifest.keys(); + + while(keys.hasMoreElements()) + { + header = keys.nextElement(); + if(oldManifest.get(header) != null) + { + if(newManifest.get(header).compareTo(oldManifest.get(header)) != 0) + { + raiseEvent(bundle, header, ManifestEvent.MODIFIED); + } + } + else + { + raiseEvent(bundle, header, ManifestEvent.CREATED); + created++; + } + } + + return newManifest.size() - created; + } + + /** + * This method compares a current bundle manifest with its old version to + * seek for deleted headers + * @param bundle + * @param oldManifest + */ + private void checkDeleted(Bundle bundle, + Dictionary oldManifest) + { + Dictionary newManifest = bundle.getHeaders(); + String header; + Enumeration keys = oldManifest.keys(); + + while(keys.hasMoreElements()) + { + header = keys.nextElement(); + if(newManifest.get(header) == null) + { + raiseEvent(bundle, header, ManifestEvent.DELETED); + } + } + } + + /** + * This method checks updates and changes a manifest to its new version + * if it is necessary + * @param bundle + */ + private void checkManifestChanges(Bundle bundle) + { + long id = bundle.getBundleId(); + + // Old manifest + Dictionary oldManifest = manifestMap.get(id); + + // Check created and modified headers + int size = compareHeaders(bundle, oldManifest); + if(size < oldManifest.size()) + { + // Check deleted headers + checkDeleted(bundle, oldManifest); + } + + // Replace manifest + manifestMap.put(id, bundle.getHeaders()); + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/RepositoryEvent.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/RepositoryEvent.java new file mode 100644 index 0000000..161e5e3 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/RepositoryEvent.java @@ -0,0 +1,80 @@ +package osgi.framework.monitoring.event; + +import java.util.EventObject; + +import org.osgi.framework.Bundle; + +/** + * Contains the relevant data of a RepositoryMonitor event + * @author Anibal + */ +public class RepositoryEvent extends EventObject +{ + //CONSTANTS + public static final int ENTRY_ERROR = 0; + + public static final int ENTRY_CREATE = 1; + + public static final int ENTRY_MODIFY = 2; + + public static final int ENTRY_DELETE = 3; + + private static final long serialVersionUID = 1L; + + // Bundle that raised the event + private Bundle bundle; + + // Type of event ENTRY_ERROR, ENTRY_CREATE, ENTRY_MODIFY or ENTRY_DELETE + private String name; + + /** + * Constructor + * @param obj observable that raised the event + * @param bundle bundle that raised the event + * @param name 0: ENTRY_ERROR, 1: ENTRY_CREATE, 2: ENTRY_MODIFY or + * 3: ENTRY_DELETE + */ + public RepositoryEvent(Object obj, Bundle bundle, String name) + { + super(obj); + + this.bundle = bundle; + this.name = name; + } + + /** + * @return bundle that raised the event + */ + public Bundle getBundle() + { + return bundle; + } + + /** + * @return ENTRY_ERROR, ENTRY_CREATE, ENTRY_MODIFY or ENTRY_DELETE + */ + public String getName() + { + return name; + } + + /** + * @return type 0: ENTRY_ERROR, 1: ENTRY_CREATE, 2: ENTRY_MODIFY or + * 3: ENTRY_DELETE + */ + public int getType() + { + switch(name) + { + case "ENTRY_CREATE": + return ENTRY_CREATE; + case "ENTRY_MODIFY": + return ENTRY_MODIFY; + case "ENTRY_DELETE": + return ENTRY_DELETE; + } + + return ENTRY_ERROR; + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/RepositoryMonitor.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/RepositoryMonitor.java new file mode 100644 index 0000000..4c0f408 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/RepositoryMonitor.java @@ -0,0 +1,85 @@ +package osgi.framework.monitoring.event; + +import java.nio.file.Path; +import java.nio.file.WatchEvent; +import java.util.Observable; +import java.util.Observer; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import osgi.framework.monitoring.event.filter.TypeFilterSet; +import osgi.framework.monitoring.event.impl.DirectoryMonitor; + +/** + * Will monitor the bundle repository, and will raise an event if any JAR file + * of any installed bundle is added, modified (updated) or deleted + * @author Anibal + */ +public class RepositoryMonitor extends EventMonitor implements Observer +{ + + /** + * Constructor, initialize monitoring process + * @param bundleContext OSGi BundleContext + */ + public RepositoryMonitor(BundleContext bundleContext) + { + super(bundleContext); + + initObserver(); + } + + /** + * Initialize the observation of the current directory in a different + * thread + */ + private void initObserver() + { + //run directory monitor + DirectoryMonitor dm = new DirectoryMonitor(); + Thread myThread = new Thread(dm); + myThread.start(); + + dm.addObserver(this); + } + + /** + * Initialize the TypeFilterSet values with RepositoryMonitor ones + * @param tf + */ + public void typeFilterSetDefaultConfiguration(TypeFilterSet tf) + { + if(tf.size() > 0) + { + tf.clear(); + } + + tf.addEntry(RepositoryEvent.ENTRY_ERROR, false); + tf.addEntry(RepositoryEvent.ENTRY_CREATE, false); + tf.addEntry(RepositoryEvent.ENTRY_MODIFY, false); + tf.addEntry(RepositoryEvent.ENTRY_DELETE, false); + } + + /* (non-Javadoc) + * @see java.util.Observer#update(java.util.Observable, java.lang.Object) + */ + @Override + public void update(Observable obs, Object obj) + { + Path fileName = ((Path)((WatchEvent)obj).context()); + + Bundle bundle = getBundleContext().getBundle("file:" + fileName); + + // If the changed file corresponds with a bundle JAR file it will raise + // an event + if(bundle != null) + { + RepositoryEvent fe = new RepositoryEvent(this, + bundle, + ((WatchEvent)obj).kind().name()); + + super.checkUpdate(fe, fe.getType(), fe.getBundle()); + } + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ServiceEventMod.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ServiceEventMod.java new file mode 100644 index 0000000..2b54d38 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ServiceEventMod.java @@ -0,0 +1,81 @@ +package osgi.framework.monitoring.event; + +import java.util.EventObject; + +import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceReference; + +/** + * Contains the relevant data of a ServiceRegistryMod event. OSGi + * ServiceEvent modified to store the Service object + * @author Anibal + */ +public class ServiceEventMod extends EventObject +{ + // CONSTANTS + public static final int MODIFIED = ServiceEvent.MODIFIED; + + public static final int MODIFIED_ENDMATCH = ServiceEvent.MODIFIED_ENDMATCH; + + public static final int REGISTERED = ServiceEvent.REGISTERED; + + public static final int UNREGISTERED = ServiceEvent.UNREGISTERING; + + private static final long serialVersionUID = 1L; + + // Type of event 2: MODIFIED, 8:MODIFIED_ENDMATCH, 1: REGISTERED, + // 4: UNREGISTERED + private int type; + + // Service reference that raised the event + private ServiceReference reference; + + // Service object that raised the event + private Object service; + + /** + * Constructor + * @param source observable that raised the event + * @param type 2: MODIFIED, 8:MODIFIED_ENDMATCH, 1: REGISTERED, + * 4: UNREGISTERED + * @param reference service reference that raised the event + * @param service service object that raised the event + */ + public ServiceEventMod(Object source, + int type, + ServiceReference reference, + Object service) + { + super(source); + + this.type = type; + this.reference = reference; + this.service = service; + } + + /** + * @return type 2: MODIFIED, 8:MODIFIED_ENDMATCH, 1: REGISTERED, + * 4: UNREGISTERED + */ + public int getType() + { + return type; + } + + /** + * @return service reference that raised the event + */ + public ServiceReference getServiceReference() + { + return reference; + } + + /** + * @return service object that raised the event + */ + public Object getService() + { + return service; + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ServiceRegistryMonitor.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ServiceRegistryMonitor.java new file mode 100644 index 0000000..d2bf271 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/ServiceRegistryMonitor.java @@ -0,0 +1,66 @@ +package osgi.framework.monitoring.event; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceListener; +import org.osgi.framework.ServiceReference; + +import osgi.framework.monitoring.event.filter.TypeFilterSet; + + +/** + * Will will monitor the OSGi service registry and will raise an event if any + * service is registered, modified or unregistered + * @author Anibal + */ +public class ServiceRegistryMonitor +extends EventMonitor +implements ServiceListener +{ + /** + * Constructor. Initialize the monitoring process + * @param bundleContext OSGi bundle context + */ + public ServiceRegistryMonitor(BundleContext bundleContext) + { + super(bundleContext); + + bundleContext.addServiceListener(this); + } + + /** + * Initialize the TypeFilterSet values with ServiceRegistryMonitor + * @param tf + */ + public void typeFilterSetDefaultConfiguration(TypeFilterSet tf) + { + if(tf.size() > 0) + { + tf.clear(); + } + + tf.addEntry(ServiceEvent.MODIFIED, false); + tf.addEntry(ServiceEvent.MODIFIED_ENDMATCH, false); + tf.addEntry(ServiceEvent.REGISTERED, false); + tf.addEntry(ServiceEvent.UNREGISTERING, false); + } + + /* (non-Javadoc) + * @see org.osgi.framework.ServiceListener#serviceChanged + * (org.osgi.framework.ServiceEvent) + */ + public void serviceChanged(ServiceEvent se) + { + ServiceReference reference = se.getServiceReference(); + + ServiceEventMod sem = new ServiceEventMod(this, + se.getType(), + reference, + getBundleContext().getService(reference)); + + super.checkUpdate(sem, + se.getType(), + se.getServiceReference().getBundle()); + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/StateMonitor.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/StateMonitor.java new file mode 100644 index 0000000..061695a --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/StateMonitor.java @@ -0,0 +1,59 @@ +package osgi.framework.monitoring.event; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.BundleListener; + +import osgi.framework.monitoring.event.filter.TypeFilterSet; + + +/** + * Will raise an event if there is any change in the state of any bundle + * @author Anibal + */ +public class StateMonitor extends EventMonitor implements BundleListener +{ + + /** + * Constructor. Initialize the monitoring process + * @param bundleContext OSGi BundleContext + */ + public StateMonitor(BundleContext bundleContext) + { + super(bundleContext); + + bundleContext.addBundleListener(this); + } + + /** + * Initialize the TypeFilterSet values with ServiceRegistryMonitor + * @param tf + */ + public void typeFilterSetDefaultConfiguration(TypeFilterSet tf) + { + if(tf.size() > 0) + { + tf.clear(); + } + + tf.addEntry(BundleEvent.INSTALLED, false); + tf.addEntry(BundleEvent.LAZY_ACTIVATION, false); + tf.addEntry(BundleEvent.RESOLVED, false); + tf.addEntry(BundleEvent.STARTED, false); + tf.addEntry(BundleEvent.STARTING, false); + tf.addEntry(BundleEvent.STOPPED, false); + tf.addEntry(BundleEvent.STOPPING, false); + tf.addEntry(BundleEvent.UNINSTALLED, false); + tf.addEntry(BundleEvent.UNRESOLVED, false); + tf.addEntry(BundleEvent.UPDATED, false); + } + + /* (non-Javadoc) + * @see org.osgi.framework.BundleListener#bundleChanged + * (org.osgi.framework.BundleEvent) + */ + public void bundleChanged(BundleEvent be) + { + super.checkUpdate(be, be.getType(), be.getBundle()); + } +} \ No newline at end of file diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/BundleFilterSet.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/BundleFilterSet.java new file mode 100644 index 0000000..eb7517f --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/BundleFilterSet.java @@ -0,0 +1,13 @@ +package osgi.framework.monitoring.event.filter; + +import osgi.framework.monitoring.event.filter.BundleFilterSet; + +/** + * Classes that inherit form this one filter events depending on the bundle + * that generated it + * @author Anibal + */ +public abstract class BundleFilterSet +{ + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/IdFilterSet.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/IdFilterSet.java new file mode 100644 index 0000000..371a318 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/IdFilterSet.java @@ -0,0 +1,54 @@ +package osgi.framework.monitoring.event.filter; + +import java.util.HashMap; +import java.util.Map; + +/** + * This class filter events depending on the id bundle that raised it + * @author Anibal + */ +public class IdFilterSet extends BundleFilterSet +{ + + // Stores id and the correspondent value + Map filter; + + /** + * Constructor + */ + public IdFilterSet() + { + filter = new HashMap(); + } + + /** + * It will add or modify the mode (opened or closed) associated with an id + * bundle. An opened value will allow all events related to that id, while + * a closed one will block them + * @param idBundle + * @param mode True: opened, False: closed + */ + public void addEntry(long idBundle, Boolean mode) + { + // Adds or modifies + filter.put(idBundle, mode); + } + + /** + * Return the value associated with idBundle + * @param idBundle + * @return mode True: opened, False: closed, null if doesn't exist + */ + public boolean isOpen(long idBundle) + { + Boolean open = filter.get(idBundle); + + if(open == null) + { + return true; + } + + return open; + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/NameFilterSet.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/NameFilterSet.java new file mode 100644 index 0000000..1ec759a --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/NameFilterSet.java @@ -0,0 +1,54 @@ +package osgi.framework.monitoring.event.filter; + + +import java.util.HashMap; +import java.util.Map; + +/** + * This class filter events depending on the name of the bundle that raised it + * @author Anibal + */ +public class NameFilterSet extends BundleFilterSet +{ + // Stores name and correspondent value + private Map filter; + + /** + * Constructor + */ + public NameFilterSet() + { + filter = new HashMap(); + } + + /** + * It will add or modify the mode (opened or closed) associated with name + * of a bundle. An opened value will allow all events related to that name, + * while a closed one will block them + * @param nameBundle + * @param mode True: opened, False: closed + */ + public void addEntry(String nameBundle, Boolean mode) + { + // Adds or modifies + filter.put(nameBundle, mode); + } + + /** + * Return the value associated with nameBundle + * @param nameBundle + * @return mode True: opened, False: closed, null if it doesn't exist + */ + public boolean isOpen(String nameBundle) + { + Boolean open = filter.get(nameBundle); + + if(open == null) + { + return true; + } + + return open; + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/TypeFilterSet.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/TypeFilterSet.java new file mode 100644 index 0000000..dc4ee5f --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/filter/TypeFilterSet.java @@ -0,0 +1,102 @@ +package osgi.framework.monitoring.event.filter; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + + +/** + * This class can block or allow events depending on their type + * @author Anibal + */ +public class TypeFilterSet +{ + // Stores type and corespondent value + Map filter; + + /** + * Constructor + */ + public TypeFilterSet() + { + filter = new HashMap(); + } + + /** + * This method will add or modify the mode (opened or closed) associated + * with a type of event. An opened value will allow all events of that + * kind, while a closed one will block them + * @param type + * @param mode True: opened, False: closed + */ + public void addEntry(int type, boolean mode) + { + //adds or modifies + filter.put(type, mode); + } + + /** + * Reset all filter with a specified value + * @param mode value + */ + public void resetTypeFilter(boolean mode) + { + Iterator> entries = + filter.entrySet().iterator(); + Map.Entry entry; + + while (entries.hasNext()) + { + entry = entries.next(); + entry.setValue(mode); + } + } + + /** + * Reset filter with opened value + */ + public void openTypeFilter() + { + resetTypeFilter(true); + } + + /** + * Reset filter with closed value + */ + public void closeTypeFilter() + { + resetTypeFilter(false); + } + + /** + * Return the value associated with type + * @param type + * @return mode True: opened, False: closed + */ + public boolean isOpen(int type) + { + Boolean open = filter.get(type); + + if(open == null) + { + return true; + } + + return open; + } + + /** + * @return size of filter + */ + public int size() + { + return filter.size(); + } + + /** + * Remove all entries from filter + */ + public void clear() + { + filter.clear(); + } +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/ClassEditor.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/ClassEditor.java new file mode 100644 index 0000000..f64e98d --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/ClassEditor.java @@ -0,0 +1,50 @@ +package osgi.framework.monitoring.event.impl; + +import java.util.ArrayList; + +import javassist.CannotCompileException; +import javassist.expr.ExprEditor; +import javassist.expr.FieldAccess; + +/** + * This class edits other classes to call DataFieldUpdate methods where all + * modifications of a data field is made + * @author Anibal + */ +public class ClassEditor extends ExprEditor +{ + + // Contains all data field names that are going to be edited + private ArrayList fieldsClass; + + // Name of the class that is going to be edited + private String className; + + /** + * @param className name of the class to be edited + * @param fieldsClass all data field names to be edited + */ + public ClassEditor(String className, ArrayList fieldsClass) + { + this.className = className; + + this.fieldsClass = fieldsClass; + } + + public void edit(FieldAccess f) throws CannotCompileException + { + // If a modification of a field on the list is made + if(f.isWriter() && (fieldsClass.contains(f.getFieldName()))) + { + // Add after the modification line a call to DataFieldUpdate method + // if that service is previously gotten. The parameters for such + // method are the modified field, class name and modified field + // name + f.replace("$_ = $proceed($$);if(dfu != null) dfu.update("+ + f.getFieldName()+ + ", \""+className+"\", \""+ + f.getFieldName()+"\");"); + } + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/ClassWeaver.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/ClassWeaver.java new file mode 100644 index 0000000..b23e92f --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/ClassWeaver.java @@ -0,0 +1,182 @@ +package osgi.framework.monitoring.event.impl; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javassist.ByteArrayClassPath; +import javassist.CannotCompileException; +import javassist.ClassClassPath; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtField; +import javassist.CtMethod; +import javassist.NotFoundException; + +import org.osgi.framework.ServiceReference; +import org.osgi.framework.hooks.weaving.*; + +import osgi.framework.monitoring.event.DataFieldUpdate; + +/** + * This class implements the OSGi WeavingHook. WeavingHook must be registered + * as a service to be able to work. It is used to get all classes that are + * loaded in the JVM. Then, it modifies previously specified classes to add + * instrumentation in them. This instrumentation will consist in get the + * DataFieldUpdate service and call the update method if there is any change in + * previously specified fields + * @author Anibal + */ +public class ClassWeaver implements WeavingHook +{ + + // Contains all fields and correspondent classes that are going to be + // instrumented + private ArrayList fields; + + /** + * Constructor + * @param fields all data field names and correspondent class names that + * are going to be instrumented + */ + public ClassWeaver(ArrayList fields) + { + this.fields = fields; + } + + /* (non-Javadoc) + * @see org.osgi.framework.hooks.weaving.WeavingHook#weave + * (org.osgi.framework.hooks.weaving.WovenClass) + */ + @Override + public void weave(WovenClass wc) + { + // Get all fields that must be instrumented from this class + ArrayList fieldsClass = getFieldName(wc.getClassName()); + + // If not null, means that this is the class and field or fields we are + // looking for + if(fieldsClass != null) + { + // Add necessary imports to the bundle + List imports = wc.getDynamicImports(); + imports.add("osgi.framework.monitoring.event;version=\"1.0.0\""); + imports.add("javassist.runtime"); + + // Initialize Javassist container of classes + ClassPool cp = ClassPool.getDefault(); + cp.appendSystemPath(); + + // Insert instrumented class + cp.insertClassPath(new ByteArrayClassPath(wc.getClassName(), + wc.getBytes())); + // Insert OSGi ServiceReference to be able to get services from + // this class + cp.insertClassPath(new ClassClassPath(ServiceReference.class)); + // Insert DataFieldUpdate, the service that we are going to use to + // alert the monitoring framework + cp.insertClassPath(new ClassClassPath(DataFieldUpdate.class)); + + try + { + // Get the CtClass objects from the pool + CtClass cc = cp.get(wc.getClassName()); + CtClass srcc = cp.get(ServiceReference.class.getName()); + CtClass dfmcc = cp.get(DataFieldUpdate.class.getName()); + + // New fields for ServiceReference and DataFieldUpdate + CtField srf = new CtField(srcc, "sr", cc); + CtField dfmf = new CtField(dfmcc, "dfu", cc); + + // Add these fields to the instrumented class + cc.addField(srf); + cc.addField(dfmf); + + // Get all methods from instrumented class + CtMethod[] behaviors = cc.getDeclaredMethods(); + + // This class will instrument every modification within the + // list of fields + ClassEditor classEditor = new ClassEditor(wc.getClassName(), + fieldsClass); + + // for all methods + for(int i = 0; i < behaviors.length; i++) + { + // Insert in the beginning line to get DataFieldUpdate + // service + behaviors[i].insertBefore("sr = org.osgi.framework." + + "FrameworkUtil.getBundle(this.getClass())." + + "getBundleContext().getServiceReference(osgi." + + "framework.monitoring.event.DataFieldUpdate." + + "class.getName()); if(sr != null) {dfu = ("+ + DataFieldUpdate.class.getName()+ + ")(org.osgi.framework.FrameworkUtil.getBundle" + + "(this.getClass()).getBundleContext()." + + "getService(sr));}"); + // instrument all fields to call update method within + // DataFieldUpdate service + behaviors[i].instrument(classEditor); + // Insert in the end line to unget DataFieldUpdate service + behaviors[i].insertAfter("if(sr != null) org.osgi." + + "framework.FrameworkUtil.getBundle(this." + + "getClass()).getBundleContext().ungetService(sr);" + ); + } + + // Transform instrumented class into array of bytes + byte[] b = cc.toBytecode(); + + // Detach all used classes from pool + cc.detach(); + srcc.detach(); + dfmcc.detach(); + + // Modify instrumented class + wc.setBytes(b); + } + catch (NotFoundException e) + { + e.printStackTrace(); + } + catch (IOException e) + { + e.printStackTrace(); + } + catch (CannotCompileException e) + { + e.printStackTrace(); + } + } + } + + /** + * Get fields to be instrumented from a class + * @param className + * @return null if there is there is no correspondence between fields + * stored and class name + */ + private ArrayList getFieldName(String className) + { + ArrayList fieldsClass = new ArrayList(); + + // For all fields to be instrumented + for(int i = 0; i < fields.size(); i++) + { + if(className.compareTo(fields.get(i).getClassName()) == 0) + { + fieldsClass.add(fields.get(i).getFieldName()); + } + } + + if(fieldsClass.size() > 0) + { + return fieldsClass; + } + else + { + return null; + } + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/DirectoryMonitor.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/DirectoryMonitor.java new file mode 100644 index 0000000..77fcb11 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/DirectoryMonitor.java @@ -0,0 +1,82 @@ +package osgi.framework.monitoring.event.impl; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.Observable; + +/** + * This class performs observation of all changes within a directory + * @author Anibal + */ +public class DirectoryMonitor extends Observable implements Runnable +{ + + /* (non-Javadoc) + * @see java.lang.Runnable#run() + */ + @Override + public void run() + { + try + { + monitorDirectory(); + } catch (IOException e) + { + e.printStackTrace(); + } catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + /** + * This method continuously performs observation of directory changes + * @throws IOException + * @throws InterruptedException + */ + public void monitorDirectory() throws IOException, InterruptedException + { + // Get running directory + Path tmpPath = Paths.get(System.getProperty("user.dir")); + + WatchService watchService = FileSystems.getDefault().newWatchService(); + + // Register service for create, modify and delete operations + tmpPath.register( + watchService, + StandardWatchEventKinds.ENTRY_CREATE, + StandardWatchEventKinds.ENTRY_MODIFY, + StandardWatchEventKinds.ENTRY_DELETE); + + /* + * Keep polling for events on the watched directory, + */ + while(true) + { + WatchKey key = watchService.take(); + + // Poll all the events queued for the key + for ( WatchEvent event: key.pollEvents()) + { + setChanged(); + notifyObservers(event); + } + + // Reset is invoked to put the key back to ready state + boolean valid = key.reset(); + + // If the key is invalid, just exit. + if ( !valid) + { + break; + } + } + } + +} diff --git a/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/MonitoredField.java b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/MonitoredField.java new file mode 100644 index 0000000..40b0af3 --- /dev/null +++ b/osgi.framework.monitoring/src/osgi/framework/monitoring/event/impl/MonitoredField.java @@ -0,0 +1,43 @@ +package osgi.framework.monitoring.event.impl; + +/** + * This class stores instrumented field data + * @author Anibal + */ +public class MonitoredField +{ + + // Name of the field's class + private String className; + + // Instrumented field name + private String fieldName; + + /** + * @param className name of the field's class + * @param fieldName name of the instrumented field + */ + public MonitoredField(String className, String fieldName) + { + this.className = className; + + this.fieldName = fieldName; + } + + /** + * @return name of the field's class + */ + public String getClassName() + { + return className; + } + + /** + * @return instrumented field name + */ + public String getFieldName() + { + return fieldName; + } + +}