You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ja...@apache.org on 2012/10/24 10:57:34 UTC

svn commit: r1401589 - in /ace/trunk/org.apache.ace.server.log.ui: bnd.bnd src/org/apache/ace/server/log/ui/LogViewerExtension.java

Author: jawi
Date: Wed Oct 24 08:57:34 2012
New Revision: 1401589

URL: http://svn.apache.org/viewvc?rev=1401589&view=rev
Log:
ACE-295: improve log viewer in web UI. Thanks to Sander D for implementing this.


Modified:
    ace/trunk/org.apache.ace.server.log.ui/bnd.bnd
    ace/trunk/org.apache.ace.server.log.ui/src/org/apache/ace/server/log/ui/LogViewerExtension.java

Modified: ace/trunk/org.apache.ace.server.log.ui/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.server.log.ui/bnd.bnd?rev=1401589&r1=1401588&r2=1401589&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.server.log.ui/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.server.log.ui/bnd.bnd Wed Oct 24 08:57:34 2012
@@ -4,7 +4,7 @@
 	org.apache.ace.log;version=latest,\
 	org.apache.ace.client.repository.api;version=latest,\
 	org.apache.ace.server.log.store.api;version=latest,\
-	com.vaadin,\
+	com.vaadin;version=latest,\
 	org.apache.ace.webui.vaadin;version=latest
 Private-Package: org.apache.ace.server.log.ui
 Bundle-Activator: org.apache.ace.server.log.ui.Activator

Modified: ace/trunk/org.apache.ace.server.log.ui/src/org/apache/ace/server/log/ui/LogViewerExtension.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.server.log.ui/src/org/apache/ace/server/log/ui/LogViewerExtension.java?rev=1401589&r1=1401588&r2=1401589&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.server.log.ui/src/org/apache/ace/server/log/ui/LogViewerExtension.java (original)
+++ ace/trunk/org.apache.ace.server.log.ui/src/org/apache/ace/server/log/ui/LogViewerExtension.java Wed Oct 24 08:57:34 2012
@@ -21,6 +21,8 @@ package org.apache.ace.server.log.ui;
 import java.io.IOException;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Dictionary;
 import java.util.Enumeration;
@@ -39,29 +41,41 @@ import org.apache.ace.webui.NamedObject;
 import org.apache.ace.webui.UIExtensionFactory;
 import org.osgi.service.log.LogService;
 
+import com.vaadin.data.Container.Filterable;
+import com.vaadin.data.Property;
+import com.vaadin.data.util.filter.SimpleStringFilter;
+import com.vaadin.event.FieldEvents.TextChangeEvent;
+import com.vaadin.event.FieldEvents.TextChangeListener;
 import com.vaadin.ui.Component;
+import com.vaadin.ui.HorizontalLayout;
 import com.vaadin.ui.Label;
 import com.vaadin.ui.Table;
 import com.vaadin.ui.TextArea;
+import com.vaadin.ui.TextField;
 import com.vaadin.ui.VerticalLayout;
 
+//import com.vaadin.data.util.
+
 /**
  * Provides a simple AuditLog viewer for targets.
  */
 public class LogViewerExtension implements UIExtensionFactory {
-    
+
     private static final String CAPTION = "LogViewer";
 
     private static final String COL_TIME = "Time";
     private static final String COL_TYPE = "Type";
     private static final String COL_PROPERTIES = "Properties";
-    
+
     private static final String FILL_AREA = "100%";
-    
+    private Table m_table;
+
     private volatile LogStore m_store;
     private volatile LogService m_logService;
 
-    /** contains a mapping of event type to a string representation of that type. */
+    /**
+     * contains a mapping of event type to a string representation of that type.
+     */
     private final Map<Integer, String> m_eventTypeMapping = new HashMap<Integer, String>();
 
     /**
@@ -69,57 +83,105 @@ public class LogViewerExtension implemen
      */
     public Component create(Map<String, Object> context) {
         RepositoryObject object = getRepositoryObjectFromContext(context);
-        if (object instanceof StatefulTargetObject && !((StatefulTargetObject) object).isRegistered()) {
+        if (object instanceof StatefulTargetObject
+            && !((StatefulTargetObject) object).isRegistered()) {
             VerticalLayout result = new VerticalLayout();
             result.setCaption(CAPTION);
-            result.addComponent(new Label("This target is not yet registered, so it has no log."));
+            result.addComponent(new Label(
+                "This target is not yet registered, so it has no log."));
             return result;
         }
 
-        Table table = new Table();
-        table.setWidth(FILL_AREA);
-        table.setHeight(FILL_AREA);
-        table.setCaption(CAPTION);
-        table.addContainerProperty(COL_TIME, Date.class, null);
-        table.addContainerProperty(COL_TYPE, String.class, null);
-        table.addContainerProperty(COL_PROPERTIES, TextArea.class, null);
-        table.setColumnExpandRatio(COL_PROPERTIES, 1);
+        m_table = new Table() {
+            @Override
+            protected String formatPropertyValue(Object rowId, Object colId, Property property) {
+                DateFormat formatter = SimpleDateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, getApplication().getLocale());
+                if (COL_TIME.equals(colId)) {
+                    return formatter.format(property.getValue());
+                }
+                return super.formatPropertyValue(rowId, colId, property);
+            }
+        };
+        m_table.setWidth(FILL_AREA);
+        m_table.setHeight(FILL_AREA);
+        m_table.addContainerProperty(COL_TIME, Date.class, null, "Time", null, null);
+        m_table.addContainerProperty(COL_TYPE, String.class, null, "Type", null, null);
+        m_table.addContainerProperty(COL_PROPERTIES, TextArea.class, null, "Properties", null, null);
+
+        m_table.setColumnExpandRatio(COL_PROPERTIES, 2);
+        m_table.setColumnExpandRatio(COL_TYPE, 1);
+        m_table.setColumnExpandRatio(COL_TIME, 1);
+        m_table.setColumnCollapsingAllowed(true);
+
         try {
-            fillTable(object, table);
+            fillTable(object, m_table);
+            // Sort on time in descending order...
+            m_table.setSortAscending(false);
+            m_table.setSortContainerPropertyId(COL_TIME);
         }
         catch (IOException ex) {
             m_logService.log(LogService.LOG_WARNING, "Log viewer failed!", ex);
         }
-        return table;
+
+        TextField tf = makeTextField(COL_TYPE);
+        TextField pf = makeTextField(COL_PROPERTIES);
+
+        HorizontalLayout filters = new HorizontalLayout();
+        filters.setSpacing(true);
+        filters.addComponent(tf);
+        filters.addComponent(pf);
+
+        // main holds the two components:
+        VerticalLayout main = new VerticalLayout();
+        main.setCaption(CAPTION);
+        main.setSpacing(true);
+
+        main.addComponent(filters);
+        main.addComponent(m_table);
+        return main;
     }
 
     /**
-     * Fills the table with all log entries for the given repository object.
+     * Returns a string representation of the given event's type.
      * 
-     * @param object the repository object to get the log for, cannot be <code>null</code>;
-     * @param table the table to fill, cannot be <code>null</code>.
-     * @throws IOException in case of I/O problems accessing the log store.
+     * @param event
+     *            the event to get the type for, cannot be <code>null</code>.
+     * @return a string representation of the event's type, never <code>null</code>.
      */
-    private void fillTable(RepositoryObject object, Table table) throws IOException {
-        String id = object.getAttribute(TargetObject.KEY_ID);
-        List<LogDescriptor> desc = m_store.getDescriptors(id);
-        if (desc != null) {
-            for (LogDescriptor log : desc) {
-                for (LogEvent event : m_store.get(log)) {
-                    table.addItem(
-                        new Object[] { new Date(event.getTime()), getEventType(event), getProperties(event) }, null);
+    final String getEventType(LogEvent event) {
+        if (m_eventTypeMapping.isEmpty()) {
+            // Lazily create a mapping of value -> name of all event-types...
+            for (Field f : AuditEvent.class.getFields()) {
+                if (((f.getModifiers() & Modifier.STATIC) != 0) && (f.getType() == Integer.TYPE)) {
+                    try {
+                        Integer value = (Integer) f.get(null);
+                        m_eventTypeMapping.put(value, normalize(f.getName()));
+                    }
+                    catch (IllegalAccessException e) {
+                        // Should not happen, as all fields are public on an
+                        // interface; otherwise we simply ignore this field...
+                        m_logService.log(LogService.LOG_DEBUG, "Failed to access public field of interface?!", e);
+                    }
                 }
             }
         }
+
+        String type = m_eventTypeMapping.get(event.getType());
+        if (type == null) {
+            type = Integer.toString(event.getType());
+        }
+
+        return type;
     }
 
     /**
      * Creates a {@link TextArea} with a dump of the given event's properties.
      * 
-     * @param event the event to create a textarea for, cannot be <code>null</code>.
+     * @param event
+     *            the event to create a textarea for, cannot be <code>null</code>.
      * @return a {@link TextArea} instance, never <code>null</code>.
      */
-    private TextArea getProperties(LogEvent event) {
+    final TextArea getProperties(LogEvent event) {
         Dictionary props = event.getProperties();
 
         TextArea area = new TextArea("", dumpProperties(props));
@@ -131,10 +193,15 @@ public class LogViewerExtension implemen
         return area;
     }
 
+    final Date getTime(LogEvent event) {
+        return new Date(event.getTime());
+    }
+
     /**
      * Dumps the given dictionary to a string by placing all key,value-pairs on a separate line.
      * 
-     * @param dict the dictionary to dump, may be <code>null</code>.
+     * @param dict
+     *            the dictionary to dump, may be <code>null</code>.
      * @return a string dump of all properties in the given dictionary, never <code>null</code>.
      */
     private String dumpProperties(Dictionary dict) {
@@ -155,38 +222,29 @@ public class LogViewerExtension implemen
     }
 
     /**
-     * Returns a string representation of the given event's type.
+     * Fills the table with all log entries for the given repository object.
      * 
-     * @param event the event to get the type for, cannot be <code>null</code>.
-     * @return a string representation of the event's type, never <code>null</code>.
+     * @param object
+     *            the repository object to get the log for, cannot be <code>null</code>;
+     * @param table
+     *            the table to fill, cannot be <code>null</code>.
+     * @throws IOException
+     *             in case of I/O problems accessing the log store.
      */
-    private String getEventType(LogEvent event) {
-        if (m_eventTypeMapping.isEmpty()) {
-            // Lazily create a mapping of value -> name of all event-types...
-            for (Field f : AuditEvent.class.getFields()) {
-                if (((f.getModifiers() & Modifier.STATIC) == Modifier.STATIC) && (f.getType() == Integer.TYPE)) {
-                    try {
-                        Integer value = (Integer) f.get(null);
-                        m_eventTypeMapping.put(value, f.getName());
-                    }
-                    catch (IllegalAccessException e) {
-                        // Should not happen, as all fields are public on an interface;
-                        // otherwise we simply ignore this field...
-                        m_logService.log(LogService.LOG_DEBUG, "Failed to access public field of interface?!", e);
-                    }
+    private void fillTable(RepositoryObject object, Table table) throws IOException {
+        String id = object.getAttribute(TargetObject.KEY_ID);
+        List<LogDescriptor> desc = m_store.getDescriptors(id);
+        if (desc != null) {
+            for (LogDescriptor log : desc) {
+                for (LogEvent event : m_store.get(log)) {
+                    table.addItem(new Object[] { getTime(event), getEventType(event), getProperties(event) }, null);
                 }
             }
         }
-
-        String type = m_eventTypeMapping.get(event.getType());
-        if (type == null) {
-            type = Integer.toString(event.getType());
-        }
-
-        return type;
     }
 
-    private RepositoryObject getRepositoryObjectFromContext(Map<String, Object> context) {
+    private RepositoryObject getRepositoryObjectFromContext(
+        Map<String, Object> context) {
         Object contextObject = context.get("object");
         if (contextObject == null) {
             throw new IllegalStateException("No context object found");
@@ -195,7 +253,34 @@ public class LogViewerExtension implemen
         // me) why ace is using either the object directly or wraps it in a
         // NamedObject first.
         // Its unclear when it does which so for now we cater for both.
-        return (contextObject instanceof NamedObject ? ((NamedObject) contextObject).getObject()
-            : (RepositoryObject) contextObject);
+        return (contextObject instanceof NamedObject ? ((NamedObject) contextObject)
+            .getObject() : (RepositoryObject) contextObject);
+    }
+
+    private TextField makeTextField(final String colType) {
+        TextField t = new TextField(colType);
+
+        t.addListener(new TextChangeListener() {
+            SimpleStringFilter filter = null;
+
+            public void textChange(TextChangeEvent event) {
+                Filterable f = (Filterable) m_table.getContainerDataSource();
+
+                // Remove old filter
+                if (filter != null) {
+                    f.removeContainerFilter(filter);
+                }
+                // Set new filter for the "Name" column
+                filter = new SimpleStringFilter(colType, event.getText(), true /* ignoreCase */, false /* onlyMatchPrefix */);
+
+                f.addContainerFilter(filter);
+            }
+        });
+
+        return t;
+    }
+    
+    private String normalize(String input) {
+        return input.toLowerCase().replaceAll("_", " ");
     }
 }