FELIX-151

Improve remote logger panel whith colored jtree and jtable



git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@448510 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/mosgi.console.component/pom.xml b/mosgi.console.component/pom.xml
index 9a3ecd5..4397381 100644
--- a/mosgi.console.component/pom.xml
+++ b/mosgi.console.component/pom.xml
@@ -43,7 +43,8 @@
 						  javax.management;specification-version="1.0.0",
 						  javax.swing;specification-version="1.0.0",
 						  javax.swing.table;specification-version="1.0.0",
-						  org.osgi.framework;specification-version="1.0.0"
+						  org.osgi.framework;specification-version="1.0.0",
+						  javax.swing.tree;specification-version="1.0.0"
 						</importPackage>
           </osgiManifest>
         </configuration>
diff --git a/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/Activator.java b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/Activator.java
index 94b1d81..9530341 100644
--- a/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/Activator.java
+++ b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/Activator.java
@@ -1,45 +1,57 @@
-/* 
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.    
-*/
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
 package org.apache.felix.mosgi.console.component;
 
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.apache.felix.mosgi.console.ifc.CommonPlugin;
+import java.lang.String;
 
-public class Activator implements BundleActivator
-{
-    private BundleContext m_context = null;
+public class Activator implements BundleActivator {
+  
+  public void start(BundleContext context) throws Exception{ 
+    String propVal=new String("both");
+    String propValue=context.getProperty("mosgi.jmxconsole.remotelogger.componentfilter");
+    if (propValue!=null) {
+      if (propValue.equals("treeonly") | propValue.equals("tableonly") | propValue.equals("both") | propValue.equals("none")) {
+        propVal=propValue;
+      }else {
+        propVal="both";
+      }
+    }
 
-    public void start(BundleContext context) throws Exception
-    {
-        m_context = context;
-        m_context.registerService( CommonPlugin.class.getName(), new RemoteLogger(), null);
+    if (propVal.equals("treeonly") | propVal.equals("both")) {
+      context.registerService(CommonPlugin.class.getName(), new RemoteLogger_jtree(context), null);
+    }
+    if (propVal.equals("tableonly") | propVal.equals("both")) {
+      context.registerService(CommonPlugin.class.getName(), new RemoteLogger_jtable(), null);
+    }
+  }
+
+  public void stop(BundleContext context) {
+  }
+
 //        m_context.registerService( Plugin.class.getName(), new NodeDetails(), null);
 //        m_context.registerService( Plugin.class.getName(), new BundleListPanel(), null);
-
+//
 //        m_context.registerService( CommonPlugin.class.getName(), new OBRPlugin(context), null);
-
-        //        m_context.registerService( Plugin.class.getName(), new MemoryLauncher(context), null);
+//
+//        m_context.registerService( Plugin.class.getName(), new MemoryLauncher(context), null);
 //        m_context.registerService( Plugin.class.getName(), new LinuxDetails(), null);
-    }
+//
 
-    public void stop(BundleContext context)
-    {
-    }
 }
diff --git a/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/JtableCellRenderer.java b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/JtableCellRenderer.java
new file mode 100644
index 0000000..2d95879
--- /dev/null
+++ b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/JtableCellRenderer.java
@@ -0,0 +1,60 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.felix.mosgi.console.component;
+
+import org.osgi.framework.Bundle;
+
+import java.util.Hashtable;
+import java.awt.Color;
+import javax.swing.JTable;
+import javax.swing.JLabel;
+import javax.swing.table.TableCellRenderer;
+import java.awt.Component;
+
+public class JtableCellRenderer extends JLabel implements TableCellRenderer {
+
+  private Hashtable eventName=new Hashtable();
+
+  public JtableCellRenderer() {
+    super();
+    eventName.put(new Integer( Bundle.ACTIVE      ), Color.green  );
+    eventName.put(new Integer( Bundle.INSTALLED   ), Color.orange );
+    eventName.put(new Integer( Bundle.RESOLVED    ), Color.red    );
+    eventName.put(new Integer( Bundle.STARTING    ), Color.gray   );
+    eventName.put(new Integer( Bundle.STOPPING    ), Color.gray   );
+    eventName.put(new Integer( Bundle.UNINSTALLED ), Color.black  );
+  }
+
+  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
+  						 boolean hasFocus, int row, int column) {
+    setOpaque(true);
+    if (column==0){
+      Integer state;
+      try{
+        state=new Integer(Integer.parseInt((String) table.getValueAt(row,5)));
+      }catch (NumberFormatException nfe) {
+        state=new Integer(-1);
+      }
+      setBackground((Color) eventName.get(state));
+    }
+    setText((String) value);
+
+    return this;
+  }	
+
+}
diff --git a/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/JtreeCellRenderer.java b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/JtreeCellRenderer.java
new file mode 100644
index 0000000..d6c33d9
--- /dev/null
+++ b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/JtreeCellRenderer.java
@@ -0,0 +1,101 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.felix.mosgi.console.component;
+
+import org.osgi.framework.BundleContext;
+
+import java.awt.Color;
+import javax.swing.JTree;
+import javax.swing.JLabel;
+import java.util.StringTokenizer;
+
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.TreeCellRenderer;
+import java.awt.Component;
+import javax.swing.tree.DefaultMutableTreeNode;
+import java.awt.Graphics;
+import java.util.NoSuchElementException;
+import java.awt.Font;
+import java.awt.Dimension;
+
+import javax.swing.ImageIcon;
+import java.awt.Toolkit;
+
+public class JtreeCellRenderer extends DefaultTreeCellRenderer {
+
+  private boolean isLeaf=false;
+  //private int maxL;
+
+  private String[] states=new String[]{"ACTIVE","INSTALLED","RESOLVED","STARTING","STOPPING","UNINSTALLED"};
+  private Color[] colors=new Color[]{Color.green,Color.orange,Color.red,Color.white,Color.white,Color.black};
+  private ImageIcon[] ii=new ImageIcon[6];
+
+  public JtreeCellRenderer(BundleContext bdlCtx){
+    for (int i=0 ; i<states.length ; i++){
+      this.ii[i]=new ImageIcon(Toolkit.getDefaultToolkit().getImage(bdlCtx.getBundle().getResource("icons/"+states[i]+".gif")));
+    }
+  }
+
+  public Dimension getPreferredSize() {
+    Dimension dim = super.getPreferredSize();
+    //maxL=(isLeaf)?Math.max(maxL,dim.width):maxL;
+    //
+    return (isLeaf)?dim:new Dimension(800/*maxL*/,dim.height);
+  }
+
+  public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+    this.isLeaf=leaf;
+
+    super.getTreeCellRendererComponent(tree,value,sel,expanded,leaf,row,hasFocus);
+    setOpaque(true);
+    setBackground(Color.white);
+    setFont(new Font("Monospaced",Font.BOLD,12));
+
+    StringTokenizer st=null;
+    DefaultMutableTreeNode dmtn=(DefaultMutableTreeNode)value;
+    int lvl=dmtn.getLevel(); 
+    if(lvl==3 & dmtn.getChildCount()>0){
+      st=new StringTokenizer(dmtn.getFirstChild().toString()," | ");
+    }
+    if (lvl==4){
+      st=new StringTokenizer(dmtn.toString()," | ");
+    }
+
+    if(st!=null){
+      st.nextToken();
+      st.nextToken();
+      String state=st.nextToken();
+      for (int i=0 ; i<states.length ; i++){
+        if (state.equals(states[i])){
+          if (lvl==4){
+            setIcon(ii[i]);
+	    setFont(new Font("Monospaced",Font.PLAIN,10));
+          }else{ 
+            StringTokenizer st2 = new StringTokenizer(((DefaultMutableTreeNode)dmtn.getFirstChild()).toString()," | ");
+            setToolTipText("<html><B>IP = </B>"+/*IP=<ip> Profil=<port>/<profil>*/dmtn.getParent().getParent()+"<B> Profil =</B>"+dmtn.getParent()+"<br><B>Bundle : </B>"+/*Bundle : Id=<bundleId> : <bundleSymbolicName>*/dmtn+"<br><B>Date : </B>"+/*<date> - <time>*/st2.nextToken()+" - "+st2.nextToken()+"<br><B>State : </B>"+/*<bundleState>*/st2.nextToken()+"<B><br>Event "+/*Event <eventNumber> : <logLevel> : <message>*/dmtn.getChildCount()+" : "+st2.nextToken()+" : "+st2.nextToken()+"</B></html>");
+            setBackground(colors[i]);
+          }
+	break;
+        }
+      }
+    }	
+	
+    return this;
+  }	
+
+}
diff --git a/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/MyTree.java b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/MyTree.java
new file mode 100644
index 0000000..4157140
--- /dev/null
+++ b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/MyTree.java
@@ -0,0 +1,48 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.console.component;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.ToolTipManager;
+import javax.swing.UIManager;
+
+public class MyTree extends JTree{
+
+  public MyTree(DefaultTreeModel dtm){
+    super(dtm);
+    //setRowHeight(0); // so DefaultTreeModel.getPreferedSize() is always call
+    ToolTipManager.sharedInstance().registerComponent(this);
+    ToolTipManager.sharedInstance().setInitialDelay(700);
+    ToolTipManager.sharedInstance().setDismissDelay(7000);
+    //ToolTipManager.setReshownDelay();
+    //ToolTipManager.setEnabled();
+  }
+
+  public String convertValueToText(Object value,boolean selected,boolean expanded,boolean leaf,int row,boolean hasFocus){
+    DefaultMutableTreeNode dmtn=(DefaultMutableTreeNode) value;
+      if (dmtn.getLevel()==3) {
+        int childNumber=dmtn.getChildCount();
+        //String lastMsg=new String((childNumber==0)?"":dmtn.getFirstChild().toString());
+        return value.toString()+" ("+dmtn.getChildCount()+" events)";//+lastMsg;
+      }else{
+        return value.toString();
+      }
+  }
+
+}
diff --git a/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtable.java b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtable.java
new file mode 100644
index 0000000..38318a1
--- /dev/null
+++ b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtable.java
@@ -0,0 +1,184 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.console.component;
+
+import org.apache.felix.mosgi.console.ifc.CommonPlugin;
+import org.apache.felix.mosgi.console.ifc.Plugin;
+//import org.apache.felix.mosgi.console.component.JtableCellRenderer;
+
+import javax.swing.table.DefaultTableModel;
+import javax.swing.JTable;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import java.awt.Component;
+
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.MBeanServerConnection;
+import javax.swing.ListSelectionModel;
+
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import java.beans.PropertyChangeEvent;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+import java.util.Vector;
+
+import java.io.PrintStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import javax.swing.JFileChooser;
+		
+import java.util.Date;
+import java.text.DateFormat;
+//import java.text.SimpleDateFormat;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.tree.DefaultMutableTreeNode;
+
+public class RemoteLogger_jtable extends DefaultTableModel implements CommonPlugin, NotificationListener{
+
+  private JTable logList;
+  private JButton jb_save;
+  private JPanel jbPanel;
+  private JPanel jp;
+  private Hashtable nodes=new Hashtable();
+
+  public void jb_actionPerformed(ActionEvent e) {
+    String compoName=((Component) e.getSource()).getName();
+	
+    if (compoName.equals("jb_save")){
+      PrintStream ps=System.out;
+      JFileChooser jfc=new JFileChooser();
+      if (jfc.showSaveDialog(null)==JFileChooser.APPROVE_OPTION & jfc.getSelectedFile()!=null){	
+      try{
+        ps=new PrintStream(jfc.getSelectedFile());
+        System.out.println("Save remote log into \""+jfc.getSelectedFile().getName()+"\""); }
+      catch (FileNotFoundException fnfe){
+        System.out.println("err : "+fnfe); }
+      }
+      int col=this.logList.getColumnCount(); // TODO : try this.getColumnCount()
+      int line=this.logList.getRowCount() - 1; // last line always empty
+      //ps.print(col+" "+line);
+      Vector tableData=new Vector();
+      tableData=this.getDataVector();
+      for (int i=0 ; i<line ; i++){
+        ps.print(i+" : ");
+        for (int j=0 ; j<col ; j++){
+	  ps.print((String) ( ((Vector) (tableData.elementAt(i))).elementAt(j) )+" | ");	
+        }
+        ps.print("\n");
+      }
+    }
+  }
+
+  public RemoteLogger_jtable (){
+    super(new String[]{"Date","Time", "Src", "Id", "Name", "State", "Lvl", "Msg"},1);
+    System.out.println("JTable Remote logger");
+   
+    this.jp=new JPanel();
+    this.jp.setLayout(new BorderLayout());
+   
+    this.jbPanel=new JPanel();
+    this.jbPanel.setSize(300,25);
+
+    this.jb_save=new JButton("Save log on file");
+    this.jb_save.setName("jb_save");
+
+    ActionListener al = new ActionListener(){
+        public void actionPerformed(ActionEvent e){
+            jb_actionPerformed(e);
+        }
+    };
+    this.jb_save.addActionListener(al);
+
+    logList=new JTable(this);
+    JtableCellRenderer cellRenderer=new JtableCellRenderer();
+    logList.setDefaultRenderer(Object.class,cellRenderer);
+
+    logList.setPreferredScrollableViewportSize(new java.awt.Dimension(600, 70));
+    
+    logList.getColumnModel().getColumn(0).setPreferredWidth(50);
+    logList.getColumnModel().getColumn(1).setPreferredWidth(40);
+    logList.getColumnModel().getColumn(2).setPreferredWidth(120);
+    logList.getColumnModel().getColumn(3).setPreferredWidth(15);
+    logList.getColumnModel().getColumn(4).setPreferredWidth(70);
+    logList.getColumnModel().getColumn(5).setPreferredWidth(15);
+    logList.getColumnModel().getColumn(6).setPreferredWidth(40);
+    logList.getColumnModel().getColumn(7).setPreferredWidth(180);    
+
+    logList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+    logList.getTableHeader().setReorderingAllowed(true);//false); // true c'est sympa pourtant... ?
+    
+    this.jbPanel.add(jb_save);
+    jp.add(this.jbPanel, BorderLayout.NORTH);
+    jp.add(new JScrollPane(logList), BorderLayout.CENTER);    
+  }
+
+  /////////////////////////////////////
+  //  Plugin Interface ////////////////
+  /////////////////////////////////////
+  public String getName(){ return "JTable Remote Logger";}
+  public Component getGUI(){return this.jp;}
+
+/* a supprimer si on enleve l'heritage CommonPlugin -> Plugin */
+  public String pluginLocation(){
+    return null;
+  }
+  public void registerServicePlugin(){}
+  public void unregisterServicePlugin(){}
+/* fin a supprimer */
+
+  
+  public void propertyChange(PropertyChangeEvent e){
+    if (e.getPropertyName().equals(Plugin.NEW_NODE_CONNECTION)){
+      try{
+        MBeanServerConnection mbs=(MBeanServerConnection)e.getNewValue();
+        if (nodes.get(mbs)==null){
+	  System.out.println("Ajout d'un listener " +mbs);
+          ((MBeanServerConnection)e.getNewValue()).addNotificationListener(new ObjectName("OSGI:name=Remote Logger"), this, null, e.getOldValue());
+          nodes.put(mbs, "ok");
+        }
+      }catch(Exception ex){
+        ex.printStackTrace();
+      }
+    }
+  }
+
+  public void handleNotification(Notification notification, Object handback) {
+    StringTokenizer st = new StringTokenizer(notification.getMessage(),":");
+    Date d=new Date(notification.getTimeStamp());
+    //DateFormat dateFormat = new SimpleDateFormat("hh'h'mm dd-MM-yy");
+    DateFormat df = DateFormat.getTimeInstance(DateFormat.MEDIUM); // utilise le format de date local
+    DateFormat df2 = DateFormat.getDateInstance(DateFormat.SHORT);
+    String id=st.nextToken();
+    String name=st.nextToken();
+    String shortName=name.substring(name.lastIndexOf(".")+1,name.length());
+    String state=st.nextToken();
+    String lvl=st.nextToken();
+    String msg=st.nextToken();
+    Object [] event = new Object []{df2.format(d),df.format(d),handback,id,shortName,state,lvl,msg};
+				    
+    this.insertRow(0,event); 
+    this.fireTableRowsInserted(0, 0);
+  }
+  
+}
diff --git a/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtree.java b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtree.java
new file mode 100644
index 0000000..a7a5863
--- /dev/null
+++ b/mosgi.console.component/src/main/java/org/apache/felix/mosgi/console/component/RemoteLogger_jtree.java
@@ -0,0 +1,187 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.console.component;
+
+import org.apache.felix.mosgi.console.ifc.CommonPlugin;
+import org.apache.felix.mosgi.console.ifc.Plugin;
+//import org.apache.felix.mosgi.console.component.JtreeCellRenderer;
+import org.apache.felix.mosgi.console.component.MyTree;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Bundle;
+
+import javax.swing.table.DefaultTableModel;
+import javax.swing.JTable;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import java.awt.Component;
+
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.MBeanServerConnection;
+import javax.swing.ListSelectionModel;
+
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import java.beans.PropertyChangeEvent;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+import java.util.Vector;
+
+import java.io.PrintStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import javax.swing.JFileChooser;
+		
+import java.util.Date;
+import java.text.DateFormat;
+//import java.text.SimpleDateFormat;
+
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.JFrame;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+
+//import org.osgi.service.prefs.Preferences;
+
+public class RemoteLogger_jtree extends DefaultTreeModel implements CommonPlugin, NotificationListener{
+
+  private MyTree logTree;
+  private JPanel jp;
+  private Hashtable nodes=new Hashtable();
+  private DefaultMutableTreeNode rootNode=new DefaultMutableTreeNode("root");
+  private Hashtable eventName=new Hashtable();
+
+  public RemoteLogger_jtree (BundleContext bdlCtx){
+    super(null);
+    setRoot(rootNode);
+    System.out.println("JTree Remote logger"); 
+
+    this.jp=new JPanel();
+    this.jp.setLayout(new BorderLayout());
+   
+    this.logTree=new MyTree(this);
+    JtreeCellRenderer treeCellRenderer=new JtreeCellRenderer(bdlCtx);
+    this.logTree.setCellRenderer(treeCellRenderer);
+    this.logTree.setLargeModel(true);
+    this.logTree.setToggleClickCount(1); 
+    this.logTree.setRootVisible(false);
+    // this create an invisible tree even if I use *expand* so...
+    // I use expand after the first insert into the tree
+  
+    jp.add(new JScrollPane(logTree), BorderLayout.CENTER);    
+    
+    eventName.put(new Integer(Bundle.ACTIVE),     "ACTIVE     ");
+    eventName.put(new Integer(Bundle.INSTALLED),  "INSTALLED  ");
+    eventName.put(new Integer(Bundle.RESOLVED),   "RESOLVED   ");
+    eventName.put(new Integer(Bundle.STARTING),   "STARTING   ");
+    eventName.put(new Integer(Bundle.STOPPING),   "STOPPING   ");
+    eventName.put(new Integer(Bundle.UNINSTALLED),"UNINSTALLED");
+  }
+
+  /////////////////////////////////////
+  //  Plugin Interface ////////////////
+  /////////////////////////////////////
+  public String getName(){ return "JTree Remote Logger";}
+  public Component getGUI(){return this.jp;}
+
+/* a supprimer si on enleve l'heritage CommonPlugin -> Plugin */
+  public String pluginLocation(){
+    return null;
+  }
+  public void registerServicePlugin(){}
+  public void unregisterServicePlugin(){}
+/* fin a supprimer */
+
+  
+  public void propertyChange(PropertyChangeEvent e){
+    if (e.getPropertyName().equals(Plugin.NEW_NODE_CONNECTION)){
+      try{
+        MBeanServerConnection mbs=(MBeanServerConnection)e.getNewValue();
+        if (nodes.get(mbs)==null){
+System.out.println("Ajout d'un listener " +mbs);
+          ((MBeanServerConnection)e.getNewValue()).addNotificationListener(new ObjectName("OSGI:name=Remote Logger"), this, null, e.getOldValue());
+          nodes.put(mbs, "ok");
+        }
+      }catch(Exception ex){
+        ex.printStackTrace();
+      }
+    }
+  }
+
+  private DefaultMutableTreeNode createIfNeed(String nodeToCreateAndGet, DefaultMutableTreeNode parent){
+    int childNumber=this.getChildCount(parent);
+    DefaultMutableTreeNode theNode=null;
+    for (int i=0 ; i<childNumber ; i++){ // is node even exist ?
+      String string_pool=((DefaultMutableTreeNode)(this.getChild(parent, i))).toString();
+      if (string_pool.equals(nodeToCreateAndGet)){
+        theNode=(DefaultMutableTreeNode) (this.getChild(parent, i));
+          break;
+      }
+    }
+    if (theNode==null){ // create the node
+      theNode=new DefaultMutableTreeNode(nodeToCreateAndGet);	
+      // Unable to set tree expand whithout a first node
+      if (rootNode.getChildCount()==0){
+        this.insertNodeInto(theNode, parent, 0);
+        logTree.expandPath(new TreePath(rootNode.getPath()));
+      }else{
+        this.insertNodeInto(theNode, parent, 0);
+      }
+    }
+  return theNode;
+  }
+
+  public void handleNotification(Notification notification, Object handback) {
+    StringTokenizer st=new StringTokenizer(handback.toString(),":");
+    String ip=st.nextToken();
+    String ref=st.nextToken();
+    
+    st = new StringTokenizer(notification.getMessage(),":");
+    Date timeDate=new Date(notification.getTimeStamp());
+    //DateFormat dateFormat = new SimpleDateFormat("hh'h'mm dd-MM-yy");
+    DateFormat df = DateFormat.getTimeInstance(DateFormat.MEDIUM); // use local date format 
+    DateFormat df2 = DateFormat.getDateInstance(DateFormat.SHORT);
+    String time=df.format(timeDate);
+    String date=df2.format(timeDate);
+
+    String id=st.nextToken();
+    String name=st.nextToken();
+    String idname=new String(id+" : "+name);
+    String state=""+eventName.get(new Integer((int) Integer.parseInt(st.nextToken())));
+    String lvl=st.nextToken();
+    String msg=st.nextToken();
+
+    // Get and maybe create parents nodes : ip, ref, idname
+    DefaultMutableTreeNode dmtn_ip=createIfNeed(ip, rootNode);
+    DefaultMutableTreeNode dmtn_ref=createIfNeed(ref, dmtn_ip);
+    DefaultMutableTreeNode dmtn_idname=createIfNeed(idname, dmtn_ref);
+
+    // insert the leaf with message under id/ref/idname
+    DefaultMutableTreeNode dmtn=new DefaultMutableTreeNode(date+" | "+time+" | "+state+" | "+lvl+" | "+msg,false); 
+    this.insertNodeInto(dmtn, dmtn_idname, 0);
+
+    this.reload(dmtn_idname);
+    }
+  
+}
diff --git a/mosgi.console.component/src/main/resources/icons/ACTIVE.gif b/mosgi.console.component/src/main/resources/icons/ACTIVE.gif
new file mode 100644
index 0000000..e4747bb
--- /dev/null
+++ b/mosgi.console.component/src/main/resources/icons/ACTIVE.gif
Binary files differ
diff --git a/mosgi.console.component/src/main/resources/icons/INSTALLED.gif b/mosgi.console.component/src/main/resources/icons/INSTALLED.gif
new file mode 100644
index 0000000..eba380d
--- /dev/null
+++ b/mosgi.console.component/src/main/resources/icons/INSTALLED.gif
Binary files differ
diff --git a/mosgi.console.component/src/main/resources/icons/RESOLVED.gif b/mosgi.console.component/src/main/resources/icons/RESOLVED.gif
new file mode 100644
index 0000000..9ec50f6
--- /dev/null
+++ b/mosgi.console.component/src/main/resources/icons/RESOLVED.gif
Binary files differ
diff --git a/mosgi.console.component/src/main/resources/icons/STARTING.gif b/mosgi.console.component/src/main/resources/icons/STARTING.gif
new file mode 100644
index 0000000..8c20575
--- /dev/null
+++ b/mosgi.console.component/src/main/resources/icons/STARTING.gif
Binary files differ
diff --git a/mosgi.console.component/src/main/resources/icons/STOPPING.gif b/mosgi.console.component/src/main/resources/icons/STOPPING.gif
new file mode 100644
index 0000000..8c20575
--- /dev/null
+++ b/mosgi.console.component/src/main/resources/icons/STOPPING.gif
Binary files differ
diff --git a/mosgi.console.component/src/main/resources/icons/UNINSTALLED.gif b/mosgi.console.component/src/main/resources/icons/UNINSTALLED.gif
new file mode 100644
index 0000000..69368e4
--- /dev/null
+++ b/mosgi.console.component/src/main/resources/icons/UNINSTALLED.gif
Binary files differ