/* * Copyright to the original author or authors. * * 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.rioproject.tools.ui.servicenotification; import org.rioproject.event.RemoteServiceEvent; import org.rioproject.log.ServiceLogEvent; import org.rioproject.monitor.ProvisionFailureEvent; import org.rioproject.monitor.ProvisionMonitorEvent; import org.rioproject.opstring.ServiceElement; import org.rioproject.sla.SLAThresholdEvent; import org.rioproject.tools.ui.Constants; import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import java.awt.*; import java.io.PrintWriter; import java.io.StringWriter; import java.text.NumberFormat; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Map; /** * A table that shows details related to a {@code RemoteServiceEvent}. * * @author Dennis Reedy */ public class RemoteServiceEventDetailsTable extends JPanel { private final NumberFormat numberFormatter; private final DetailsModel model = new DetailsModel(); private final JTable table = new JTable(); public RemoteServiceEventDetailsTable() { super(new BorderLayout(8, 8)); table.setModel(model); table.setFillsViewportHeight(true); table.setDefaultRenderer(Object.class, new MultiLineCellRenderer()); TableColumn column = table.getColumnModel().getColumn(0); column.setPreferredWidth(100); column.setMaxWidth(130); numberFormatter = NumberFormat.getNumberInstance(); numberFormatter.setGroupingUsed(false); numberFormatter.setMaximumFractionDigits(2); add(new JScrollPane(table)); } public void setRemoteServiceEventNode(RemoteServiceEventNode eventNode) { model.setRemoteServiceEventNode(eventNode); } class DetailsModel extends AbstractTableModel { private final String[] columnNames = {"Field", "Value"}; private final Map<String, String> tableData = new LinkedHashMap<String, String>(); public int getRowCount() { return tableData.size(); } void setRemoteServiceEventNode(RemoteServiceEventNode eventNode) { if(eventNode==null) { tableData.clear(); this.fireTableDataChanged(); return; } RemoteServiceEvent event = eventNode.getEvent(); tableData.clear(); String impl = "<not declared>"; Throwable thrown; if(event instanceof ProvisionFailureEvent) { String label = "ProvisionFailureEvent."+eventNode.getValueAt(0); ProvisionFailureEvent pfe = (ProvisionFailureEvent)event; ServiceElement elem = pfe.getServiceElement(); if(elem.getComponentBundle()!=null) impl = elem.getComponentBundle().getClassName(); thrown = pfe.getThrowable(); String exception = getExceptionText(thrown); tableData.put("Event", label); tableData.put("When", Constants.DATE_FORMAT.format(event.getDate())); tableData.put("Deployment", elem.getOperationalStringName()); tableData.put("Service", elem.getName()); tableData.put("Class", impl); StringBuilder builder = new StringBuilder(); for(String reason : pfe.getFailureReasons()) { if(builder.length()>0) builder.append("\n "); builder.append(reason); } tableData.put("Reason", builder.toString()); if(exception!=null) { tableData.put("Exception", exception); table.setRowHeight(tableData.size(), table.getRowHeight() * 20); } } else if(event instanceof ProvisionMonitorEvent) { String label = "ProvisionMonitorEvent."+eventNode.getValueAt(0); tableData.put("Event", label); ProvisionMonitorEvent pme = (ProvisionMonitorEvent)event; StringBuilder builder = new StringBuilder(); if(pme.getAction().equals(ProvisionMonitorEvent.Action.OPSTRING_DEPLOYED) || pme.getAction().equals(ProvisionMonitorEvent.Action.OPSTRING_UNDEPLOYED)) { StringBuilder serviceNameBuilder = new StringBuilder(); for(ServiceElement service : pme.getOperationalString().getServices()) { if(serviceNameBuilder.length()>0) { serviceNameBuilder.append(", "); } serviceNameBuilder.append(service.getName()); } builder.append(serviceNameBuilder.toString()); tableData.put("When", Constants.DATE_FORMAT.format(event.getDate())); tableData.put("Deployment", pme.getOperationalStringName()); tableData.put("Services", builder.toString()); } else { tableData.put("When", Constants.DATE_FORMAT.format(event.getDate())); tableData.put("Deployment", pme.getOperationalStringName()); tableData.put("Description", eventNode.getDescription()); } } else if(event instanceof ServiceLogEvent) { String label = "ServiceLogEvent."+eventNode.getValueAt(0); tableData.put("Event", label); ServiceLogEvent sle = (ServiceLogEvent)event; thrown = sle.getLogRecord().getThrown(); String exception = getExceptionText(thrown); tableData.put("When", Constants.DATE_FORMAT.format(event.getDate())); tableData.put("Deployment", sle.getOpStringName()); tableData.put("Service", sle.getServiceName()); tableData.put("Machine", sle.getAddress().getHostName()); tableData.put("Message", sle.getLogRecord().getLevel()+": "+sle.getLogRecord().getMessage()); if(exception!=null) { tableData.put("Exception", exception); table.setRowHeight(tableData.size(), table.getRowHeight() * 20); } } else { String label = "SLAThresholdEvent."+eventNode.getValueAt(0); tableData.put("Event", label); SLAThresholdEvent slaEvent = (SLAThresholdEvent)event; StringBuilder builder = new StringBuilder(); builder.append("low=").append(slaEvent.getSLA().getCurrentLowThreshold()); builder.append(" high=").append(slaEvent.getSLA().getCurrentHighThreshold()); tableData.put("When", Constants.DATE_FORMAT.format(event.getDate())); tableData.put("Deployment", slaEvent.getServiceElement().getOperationalStringName()); tableData.put("Service", slaEvent.getServiceElement().getName()); tableData.put("Machine", slaEvent.getHostAddress()); tableData.put("Value", numberFormatter.format(slaEvent.getCalculable().getValue())); tableData.put("Threshold Values", builder.toString()); tableData.put("Policy Handler", slaEvent.getSLAPolicyHandlerDescription()); } this.fireTableDataChanged(); } public int getColumnCount() { return columnNames.length; } public String getColumnName(int col) { return columnNames[col]; } public Object getValueAt(int row, int col) { int i = 0; String value = null; for(Map.Entry<String, String> entry : tableData.entrySet()) { if(row==i) { value = col==0?entry.getKey():entry.getValue(); break; } i++; } return value; } private String getExceptionText(Throwable thrown) { String exception = null; if(thrown!=null) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true); if (thrown.getStackTrace() != null) thrown.printStackTrace(pw); pw.flush(); sw.flush(); exception = sw.toString(); /*StringBuilder builder = new StringBuilder(); builder.append(thrown.getClass().getName()).append(": ").append(thrown.getLocalizedMessage() ).append("\n"); StackTraceElement[] trace = thrown.getStackTrace(); for (StackTraceElement aTrace : trace) builder.append(" at ").append(aTrace).append("\n"); exception = builder.toString();*/ } return exception; } } /** * A multi-line cell renderer * * @author http://blog.botunge.dk/post/2009/10/09/JTable-multiline-cell-renderer.aspx */ class MultiLineCellRenderer extends JTextArea implements TableCellRenderer { private java.util.List<java.util.List<Integer>> rowColHeight = new ArrayList<java.util.List<Integer>>(); public MultiLineCellRenderer() { setLineWrap(true); setWrapStyleWord(true); setOpaque(true); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (isSelected) { setForeground(table.getSelectionForeground()); setBackground(table.getSelectionBackground()); } else { setForeground(table.getForeground()); setBackground(table.getBackground()); } setFont(table.getFont()); if (hasFocus) { setBorder(UIManager.getBorder("Table.focusCellHighlightBorder")); if (table.isCellEditable(row, column)) { setForeground(UIManager.getColor("Table.focusCellForeground")); setBackground(UIManager.getColor("Table.focusCellBackground")); } } else { setBorder(new EmptyBorder(1, 2, 1, 2)); } setText((value == null) ? "" : value.toString()); if(getLineCount()>1) { adjustRowHeight(table, row, column); } return this; } /** * Calculate the new preferred height for a given row, and sets the height on the table. */ private void adjustRowHeight(JTable table, int row, int column) { //The trick to get this to work properly is to set the width of the column to the //textarea. The reason for this is that getPreferredSize(), without a width tries //to place all the text in one line. By setting the size with the with of the column, //getPreferredSize() returns the proper height which the row should have in //order to make room for the text. int cWidth = table.getTableHeader().getColumnModel().getColumn(column).getWidth(); setSize(new Dimension(cWidth, 1000)); int prefH = getPreferredSize().height; while (rowColHeight.size() <= row) { rowColHeight.add(new ArrayList<Integer>(column)); } java.util.List<Integer> colHeights = rowColHeight.get(row); while (colHeights.size() <= column) { colHeights.add(0); } colHeights.set(column, prefH); int maxH = prefH; for (Integer colHeight : colHeights) { if (colHeight > maxH) { maxH = colHeight; } } if (table.getRowHeight(row) != maxH) { table.setRowHeight(row, maxH); } } } }