/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.admingui.common.handlers;
import com.sun.jsftemplating.annotation.Handler;
import com.sun.jsftemplating.annotation.HandlerInput;
import com.sun.jsftemplating.annotation.HandlerOutput;
import com.sun.jsftemplating.layout.descriptors.handler.HandlerContext;
import com.sun.jsftemplating.util.Util;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.ws.rs.core.MultivaluedHashMap;
import org.glassfish.admingui.common.util.GuiUtil;
public class LogViewHandlers {
/**
* Creates a new instance of LogViewHandlers
*/
public LogViewHandlers() {
}
/**
* <p> This handler creates a Map<String, String> which contains the
* QUERY_STRING parameters that should be passed to the REST logging
* endpoint to make a query with the given constraints.</p>
*
* @param context The HandlerContext.
*/
@Handler(id = "gf.getLogQueryAttributes",
input = {
@HandlerInput(name = "InstanceName", type = String.class, required = true),
@HandlerInput(name = "LogFileName", type = String.class, required = true),
@HandlerInput(name = "LogLevel", type = String.class, required = true),
@HandlerInput(name = "FromRecord", type = Integer.class),
@HandlerInput(name = "AfterRecord", type = Boolean.class),
@HandlerInput(name = "DateEnabled", type = String.class),
@HandlerInput(name = "FromDate", type = Object.class),
@HandlerInput(name = "FromTime", type = Object.class),
@HandlerInput(name = "ToDate", type = Object.class),
@HandlerInput(name = "ToTime", type = Object.class),
@HandlerInput(name = "Loggers", type = Object.class),
@HandlerInput(name = "CustomLoggers", type = Object.class),
@HandlerInput(name = "anySearch", type = String.class),
@HandlerInput(name = "NumToDisplay", type = Integer.class),
@HandlerInput(name = "OnlyLevel", type = Boolean.class, defaultValue = "false"),
@HandlerInput(name = "LogDateSortDirection", type = Boolean.class)},
output = {
@HandlerOutput(name = "attributes", type = Map.class)})
public static void getLogQueryAttributes(HandlerContext handlerCtx) {
// Create a Map to hold the attributes
Map<String, Object> attMap = new HashMap<String, Object>();
// Attempt to read values passed in
String logFileName = (String) handlerCtx.getInputValue("LogFileName");
Integer fromRecord = (Integer) handlerCtx.getInputValue("FromRecord");
Boolean after = (Boolean) handlerCtx.getInputValue("AfterRecord");
String dateEnabledString = (String) handlerCtx.getInputValue("DateEnabled");
Object fromDate = handlerCtx.getInputValue("FromDate");
Object fromTime = handlerCtx.getInputValue("FromTime");
Object toDate = handlerCtx.getInputValue("ToDate");
Object toTime = handlerCtx.getInputValue("ToTime");
Object loggers = handlerCtx.getInputValue("Loggers");
String logLevel = (String) handlerCtx.getInputValue("LogLevel");
Object customLoggers = handlerCtx.getInputValue("CustomLoggers");
String anySearch = (String) handlerCtx.getInputValue("anySearch");
Integer numberToDisplay = (Integer) handlerCtx.getInputValue("NumToDisplay");
Boolean onlyLevel = (Boolean) handlerCtx.getInputValue("OnlyLevel");
Boolean direction = (Boolean) handlerCtx.getInputValue("LogDateSortDirection");
String instanceName = (String) handlerCtx.getInputValue("InstanceName");
notNullStringPut(attMap, "instanceName", instanceName);
if ((instanceName != null)) {
if (logFileName != null) {
Date from;
Date to;
// Convert Date/Time fields
if ((dateEnabledString != null)
&& ("enabled".equalsIgnoreCase(dateEnabledString)
|| "true".equalsIgnoreCase(dateEnabledString))) {
// Date is enabled, figure out what the values are
from = convertDateTime(handlerCtx, fromDate, fromTime);
to = convertDateTime(handlerCtx, toDate, toTime);
if ((from == null)) {
GuiUtil.handleError(handlerCtx, "Specific Date Range was chosen, however, date fields are incomplete.");
}
if (to != null && from != null) {
if (from.after(to)) {
GuiUtil.handleError(handlerCtx, "Timestamp value of 'From: ' field " + fromDate
+ " must not be greater than 'To: ' field value " + toDate);
}
}
} else {
// Date not enabled, ignore from/to dates
from = null;
to = null;
}
if ((logLevel != null) && (logLevel.trim().length() == 0)) {
logLevel = null;
}
// Convert module array to List
//List moduleList = null;
//Set moduleList = new HashSet();
String listOfModules = "";
String sep = "";
if (loggers != null) {
int len = ((Object[]) loggers).length;
if (len > 0) {
Object val;
StringBuilder sb = new StringBuilder();
for (int count = 0; count < len; count++) {
val = (((Object[]) loggers)[count]);
if ((val == null) || (val.toString().trim().length() == 0)) {
continue;
}
sb.append(sep).append(val);
sep = ",";
}
listOfModules = sb.toString();
}
}
// Add custom loggers
if ((customLoggers != null) && (customLoggers.toString().trim().length() != 0)) {
String customLoggerList = customLoggers.toString().trim();
for (String delim : CUSTOM_LOGGER_DELIMITERS) {
customLoggerList = customLoggerList.replace(delim, ",");
}
listOfModules += sep + customLoggerList;
}
if (!listOfModules.isEmpty()) {
attMap.put("listOfModules", listOfModules);
}
// Get the number to Display
if (numberToDisplay == null) {
numberToDisplay = DEFAULT_NUMBER_TO_DISPLAY;
}
// Get the direction
if (direction == null) {
direction = Boolean.FALSE;
}
// Get AfterRecord flag
if (after == null) {
// Not supplied, use direction
after = direction;
}
notNullStringPut(attMap, "logFileName", logFileName);
notNullStringPut(attMap, "startIndex", fromRecord);
notNullStringPut(attMap, "searchForward", after);//direction
notNullStringPut(attMap, "maximumNumberOfResults", numberToDisplay);
notNullStringPut(attMap, "onlyLevel", onlyLevel);
if (from != null) {
notNullStringPut(attMap, "fromTime", Long.valueOf(from.getTime()));
}
if (to != null) {
notNullStringPut(attMap, "toTime", Long.valueOf(to.getTime()));
}
notNullStringPut(attMap, "anySearch", anySearch);
notNullStringPut(attMap, "logLevel", logLevel);
notNullStringPut(attMap, "logFileRefresh", "true");
// if (moduleList != null) {
// attMap.addAll("listOfModules", moduleList);
// }
//notNullStringPut(attMap, "logFileRefresh", logFileName);
}
}
handlerCtx.setOutputValue("attributes", attMap);
}
/**
* <p> This handler creates a Map<String, String> which contains the
* QUERY_STRING parameters that should be passed to the REST logging
* endpoint to make a query with the given constraints.</p>
*
* @param context The HandlerContext.
*/
@Handler(id = "gf.processLogRecords",
input = {
@HandlerInput(name = "logRecords", type = List.class, required = true),
@HandlerInput(name = "truncate", type = Boolean.class, defaultValue = "true"),
@HandlerInput(name = "truncateLength", type = Integer.class, defaultValue = "100")},
output = {
@HandlerOutput(name = "result", type = List.class),
@HandlerOutput(name = "firstRecord", type = Integer.class),
@HandlerOutput(name = "lastRecord", type = Integer.class)})
public static void processLogRecords(HandlerContext handlerCtx) {
// Get the input...
List<Map<String, Object>> records = (List<Map<String, Object>>) handlerCtx.getInputValue("logRecords");
if (records != null) {
// Make sure there's something to do...
boolean truncate = (Boolean) handlerCtx.getInputValue("truncate");
int truncLen = (Integer) handlerCtx.getInputValue("truncateLength");
Locale locale = GuiUtil.getLocale();
// Loop through the records...
for (Map<String, Object> record : records) {
record.put("dateTime",
formatDateForDisplay(locale, new Date(new Long(
record.get("loggedDateTimeInMS").toString()))));
/*
// FIXME: Should we add this code back in? It was not being
// FIXME: used in the current version.
String msgId = (String) row.getMessageID();
String level = (String) row.getLevel();
String moduleName = (String)row.getModule();
//only SEVERE msg provoides diagnostic info.
if (level.equalsIgnoreCase("severe")) {
// NOTE: Image name/location is hard-coded
record.put("levelImage", GuiUtil.getMessage("common.errorGif"));
record.put(SHOW_LEVEL_IMAGE, new Boolean(true));
record.put("diagnosticCauses", getDiagnosticCauses(handlerCtx, msgId, moduleName));
record.put("diagnosticChecks", getDiagnosticChecks(handlerCtx, msgId, moduleName));
// record.put("diagnosticURI", getDiagnosticURI(handlerCtx, msgId));
} else {
record.put(SHOW_LEVEL_IMAGE, new Boolean(false));
record.put("diagnostic", "");
}
record.put("level", level);
record.put("productName", row.getProductName());
record.put("logger", moduleName);
*/
String message = ((String) record.get("Message")).trim();
if (truncate && (message.length() > truncLen)) {
message = message.substring(0, truncLen).concat("...\n");
}
record.put("Message", Util.htmlEscape(message));
}
}
// Set the first / last record numbers as attributes
if ((records != null) && (records.size() > 0)) {
handlerCtx.setOutputValue("firstRecord", records.get(0).get("recordNumber"));
handlerCtx.setOutputValue("lastRecord", records.get(records.size() - 1).get("recordNumber"));
//hasResults = true;
} else {
handlerCtx.setOutputValue("firstRecord", "-1");
handlerCtx.setOutputValue("lastRecord", "-1");
}
handlerCtx.setOutputValue("result", records);
}
/**
* Utility for adding non-null values to the map as a String.
*/
private static void notNullStringPut(Map<String, Object> map, String key, Object val) {
if (val != null) {
map.put(key, val.toString());
}
}
/**
* This method converts a date/time string to a Date.
*
* @param request The ServletRequest
* @param date The date as a String (or the date/time as a Date)
* @param time The time as a String (or null)
* @param vd The ViewDescriptor (for exception handling)
* @param view The View (for exception handling)
*/
protected static Date convertDateTime(HandlerContext handlerCtx, Object date, Object time) {
// If Date is already a Date, then do nothing
if (date instanceof Date) {
return (Date) date;
}
// If Date is null or empty, return null
if ((date == null) || (date.toString().trim().length() == 0)) {
return null;
}
// Get the date / time string
if ((time != null) && (time.toString().trim().length() == 0)) {
time = null;
}
String dateTime = date.toString()
+ ((time == null) ? "" : (" " + time.toString()));
DateFormat df = DateFormat.getDateInstance(
DateFormat.SHORT, GuiUtil.getLocale());
if ((time != null) && (df instanceof SimpleDateFormat)) {
SimpleDateFormat fmt = (SimpleDateFormat) df;
String formatPrefix = fmt.toLocalizedPattern();
try {
// Try w/ HH:mm:ss.SSS
date = parseDateString(
fmt, formatPrefix + TIME_FORMAT, dateTime);
} catch (ParseException ex) {
try {
// Try w/ HH:mm:ss
date = parseDateString(
fmt, formatPrefix + TIME_FORMAT_2, dateTime);
} catch (ParseException ex2) {
try {
// Try w/ HH:mm
date = parseDateString(
fmt, formatPrefix + TIME_FORMAT_3, dateTime);
} catch (ParseException ex3) {
GuiUtil.handleError(handlerCtx, "Unable to parse Date/Time: '" + dateTime + "'.");
}
}
}
} else if (time != null) {
// I don't think this ever happens
df = DateFormat.getDateTimeInstance(
DateFormat.SHORT, DateFormat.LONG, GuiUtil.getLocale());
try {
date = df.parse(dateTime);
} catch (ParseException ex) {
GuiUtil.handleError(handlerCtx, "Unable to parse Date/Time: '" + dateTime + "'.");
}
} else {
try {
date = df.parse(dateTime);
} catch (ParseException ex) {
GuiUtil.handleError(handlerCtx, "Unable to parse Date/Time: '" + dateTime + "'.");
}
}
// Return the result
Date convertDate = null;
try {
convertDate = (Date) date;
} catch (Exception ex) {
convertDate = null;
}
return convertDate;
}
/**
* This method simply takes the given SimpleDateFormat and parses the given
* String after applying the given format String.
*/
private static Date parseDateString(SimpleDateFormat fmt, String format, String dateTime) throws ParseException {
fmt.applyLocalizedPattern(format);
return fmt.parse(dateTime);
}
/**
* This method formats a log file date to a more readable date (based on
* locale).
*/
public static String formatDateForDisplay(Locale locale, Date date) {
DateFormat dateFormat = DateFormat.getDateInstance(
DateFormat.MEDIUM, locale);
if (dateFormat instanceof SimpleDateFormat) {
SimpleDateFormat fmt = (SimpleDateFormat) dateFormat;
fmt.applyLocalizedPattern(fmt.toLocalizedPattern() + TIME_FORMAT);
return fmt.format(date);
} else {
dateFormat = DateFormat.getDateTimeInstance(
DateFormat.MEDIUM, DateFormat.LONG, locale);
return dateFormat.format(date);
}
}
/**
* <p> This handler returns the first and last log record.</p>
*
* <p> Output value: "LogFileNames" -- Type:
* <code>java.util.SelectItem</code>
*
* @param context The HandlerContext.
*/
@Handler(id = "getFirstLastRecord",
input = {
@HandlerInput(name = "FirstRecord", type = String.class, required = true),
@HandlerInput(name = "LastRecord", type = String.class, required = true)},
output = {
@HandlerOutput(name = "First", type = String.class),
@HandlerOutput(name = "Last", type = String.class)})
public static void getFirstLastRecord(HandlerContext handlerCtx) {
// Get the first/last row numbers
String firstLogRow = (String) handlerCtx.getInputValue("FirstRecord");
String lastLogRow = (String) handlerCtx.getInputValue("LastRecord");
if (firstLogRow == null) {
firstLogRow = "0";
}
if (lastLogRow == null) {
lastLogRow = "0";
}
int firstRow = 0;
try {
firstRow = Integer.parseInt(firstLogRow);
int lastRow = Integer.parseInt(lastLogRow);
if (firstRow > lastRow) {
String temp = firstLogRow;
firstLogRow = lastLogRow;
lastLogRow = temp;
}
handlerCtx.setOutputValue("First", firstLogRow);
handlerCtx.setOutputValue("Last", lastLogRow);
} catch (NumberFormatException ex) {
// ignore
}
}
/**
* This method formats the diagnostic to be displayed for HTML Add '<br>' to
* each elements of the ArrayList and returns the String.
*/
protected static String formatArrayForDisplay(String[] diag) {
if ((diag == null) || (diag.length == 0)) {
return "";
}
StringBuilder buf = new StringBuilder("<br>");
for (int i = 0; i < diag.length; i++) {
buf.append((String) diag[i]);
buf.append("<br>");
}
return buf.toString();
}
/**
* <P>This method puts the current time (as a String) in the desired
* attribute. The result attribute must be specified via an attribute named
* "getTimeResultAttribute"</P>
*/
@Handler(id = "getTime",
output = {
@HandlerOutput(name = "Time", type = String.class)})
public void getTime(HandlerContext handlerCtx) {
try {
DateFormat df = DateFormat.getTimeInstance(
DateFormat.SHORT, GuiUtil.getLocale());
((SimpleDateFormat) df).applyLocalizedPattern(TIME_FORMAT);
// Set the return value
handlerCtx.setOutputValue("Time", df.format(new Date()));
} catch (Exception ex) {
GuiUtil.handleException(handlerCtx, ex);
}
}
/**
* <P>This method returns the current date (as a String). The DATE_FORMAT
* must be specified, if it is not this method will fail. You may set it to
* "short", "medium", "long", or "FULL".</P>
*
* <P>If you do not set it to one of these values, you may set it to a valid
* format string.</P>
*/
@Handler(id = "getDate",
input = {
@HandlerInput(name = "DateFormat", type = String.class, required = true)},
output = {
@HandlerOutput(name = "Date", type = String.class)})
public void getDate(HandlerContext handlerCtx) {
// Get the required attribute
String formatString = (String) handlerCtx.getInputValue("DateFormat");
// Get the type
int formatType = -1;
if (formatString.equals(GET_DATE_SHORT)) {
formatType = DateFormat.SHORT;
} else if (formatString.equals(GET_DATE_MEDIUM)) {
formatType = DateFormat.MEDIUM;
} else if (formatString.equals(GET_DATE_LONG)) {
formatType = DateFormat.LONG;
} else if (formatString.equals(GET_DATE_FULL)) {
formatType = DateFormat.FULL;
}
DateFormat df = null;
if (formatType == -1) {
df = DateFormat.getDateInstance(
DateFormat.SHORT, GuiUtil.getLocale());
((SimpleDateFormat) df).applyLocalizedPattern(formatString);
} else {
df = DateFormat.getDateInstance(
formatType, GuiUtil.getLocale());
}
// Set the return value
handlerCtx.setOutputValue("Date", df.format(new Date()));
}
/**
* <P>This method returns the formatted date (as a String). </P>
*
*/
@Handler(id = "getFormattedDateTime",
input = {
@HandlerInput(name = "Timestamp", type = String.class, required = true),
@HandlerInput(name = "AddHour", type = Boolean.class)},
output = {
@HandlerOutput(name = "Time", type = String.class),
@HandlerOutput(name = "Date", type = String.class)})
public void getFormattedDateTime(HandlerContext handlerCtx) {
String timeStamp = (String) handlerCtx.getInputValue("Timestamp");
Boolean addHour = (Boolean) handlerCtx.getInputValue("AddHour");
Date date = null;
if ((timeStamp == null) || "".equals(timeStamp)) {
date = new Date(System.currentTimeMillis());
} else {
try {
if (addHour != null) {
date = new Date(Long.parseLong(timeStamp) + ONE_HOUR);
} else {
date = new Date(Long.parseLong(timeStamp));
}
} catch (Exception ex) {
GuiUtil.getLogger().info(GuiUtil.getCommonMessage("log.error.dateFormat") + ex.getLocalizedMessage());
if (GuiUtil.getLogger().isLoggable(Level.FINE)) {
ex.printStackTrace();
}
date = new Date(System.currentTimeMillis());
}
}
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, GuiUtil.getLocale());
DateFormat tf = DateFormat.getTimeInstance(DateFormat.MEDIUM, GuiUtil.getLocale());
((SimpleDateFormat) tf).applyLocalizedPattern(" HH:mm:ss.SSS");
String ftime = tf.format(date);
String fdate = df.format(date);
handlerCtx.setOutputValue("Time", ftime);
handlerCtx.setOutputValue("Date", fdate);
}
/**
* This defines the short date format, used by DATE_FORMAT. ("short")
*/
public static final String GET_DATE_SHORT = "short";
/**
* This defines the medium date format, used by DATE_FORMAT. ("medium")
*/
public static final String GET_DATE_MEDIUM = "medium";
/**
* This defines the long date format, used by DATE_FORMAT. ("long")
*/
public static final String GET_DATE_LONG = "long";
/**
* This defines the full date format, used by DATE_FORMAT. ("full")
*/
public static final String GET_DATE_FULL = "full";
/**
* This specifies how TIME fields are input and displayed. We need to do
* this in order to get a display/input that works with milliseconds.
* Perhaps in the future we may want to just append the milliseconds?
*/
public static final String TIME_FORMAT = " HH:mm:ss.SSS";
public static final String TIME_FORMAT_2 = " HH:mm:ss";
public static final String TIME_FORMAT_3 = " HH:mm";
/**
* If the number to display is not specified, this value will be used (40).
*/
public static final Integer DEFAULT_NUMBER_TO_DISPLAY = Integer.valueOf(40);
/**
*
*/
public static final String FIRST_LOG_ROW = "firstLogRow";
public static final int FROM_RECORD = 0;
/**
*
*/
public static final String LAST_LOG_ROW = "lastLogRow";
/**
* The following constant defines the valid delimiters that can be used to
* seperate custom loggers on input. (" \t\n\r\f,;:")
*/
private static final String[] CUSTOM_LOGGER_DELIMITERS = {" \t", "\r\n", "\f", ",", ";", ":"};
/**
* The following constant defines the valid delimiters that can be used to
* seperate nvp entries on input. (" \t\n\r\f,;:")
*/
public static final String NVP_DELIMITERS = " \t\n\r\f,;:";
/**
* This is the delimiter between the property name and property value.
*/
public static final char EQUALS = '=';
/**
* This model key is set by the filter method, it is true if a level image
* should be displayed.
*/
public static final String SHOW_LEVEL_IMAGE = "showLevelImage";
/**
* This is the root directory of the alert images
*/
public static final String LEVEL_IMAGE_ROOT =
"/com_sun_web_ui/images/alerts/";
public static final long ONE_HOUR = (1000 /* ms */) * (60 /* sec */) * (60 /* min */);
}