org.apache.ace.log.server.ui.LogViewerExtension.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ace.log.server.ui.LogViewerExtension.java

Source

/*
 * 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.
 */
package org.apache.ace.log.server.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.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ace.client.repository.RepositoryObject;
import org.apache.ace.client.repository.object.TargetObject;
import org.apache.ace.client.repository.stateful.StatefulTargetObject;
import org.apache.ace.feedback.AuditEvent;
import org.apache.ace.feedback.Descriptor;
import org.apache.ace.feedback.Event;
import org.apache.ace.log.server.store.LogStore;
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.
     */
    private final Map<Integer, String> m_eventTypeMapping = new HashMap<>();

    /**
     * {@inheritDoc}
     */
    public Component create(Map<String, Object> context) {
        StatefulTargetObject target = getRepositoryObjectFromContext(context);
        if (!target.isRegistered()) {
            VerticalLayout result = new VerticalLayout();
            result.setCaption(CAPTION);
            result.addComponent(new Label("This target is not yet registered, so it has no log."));
            return result;
        }

        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(target, 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);
        }

        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;
    }

    /**
     * Returns a string representation of the given event's type.
     * 
     * @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>.
     */
    final String getEventType(Event 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>.
     * @return a {@link TextArea} instance, never <code>null</code>.
     */
    final TextArea getProperties(Event event) {
        Map<String, String> props = event.getProperties();

        TextArea area = new TextArea("", dumpProperties(props));
        area.setWidth(FILL_AREA);
        area.setRows(props.size());
        area.setWordwrap(false);
        area.setReadOnly(true);
        area.setImmediate(true);
        return area;
    }

    final Date getTime(Event event) {
        return new Date(event.getTime());
    }

    /**
     * Dumps the given dictionary to a string by placing all key,value-pairs on a separate line.
     * 
     * @param props
     *            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(Map<String, String> props) {
        StringBuilder sb = new StringBuilder();
        if (props != null) {
            for (String key : props.keySet()) {
                String value = props.get(key);

                if (sb.length() > 0) {
                    sb.append("\n");
                }
                sb.append(key).append(": ").append(value);
            }
        }
        return sb.toString();
    }

    /**
     * Fills the table with all log entries for the given repository object.
     * 
     * @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 void fillTable(RepositoryObject object, Table table) throws IOException {
        String id = object.getAttribute(TargetObject.KEY_ID);
        List<Descriptor> desc = m_store.getDescriptors(id);
        if (desc != null) {
            for (Descriptor log : desc) {
                for (Event event : m_store.get(log)) {
                    table.addItem(new Object[] { getTime(event), getEventType(event), getProperties(event) }, null);
                }
            }
        }
    }

    private StatefulTargetObject getRepositoryObjectFromContext(Map<String, Object> context) {
        Object contextObject = context.get("statefulTarget");
        if (contextObject == null) {
            throw new IllegalStateException("No context object found");
        }
        return (StatefulTargetObject) 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("_", " ");
    }
}