SessionView.java
/*
** Module : SessionView.java
** Abstract : SessionView is a view to manage sessions.
**
** Copyright (c) 2017-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- ----------------Description----------------------
** 001 SBI 20170601 Created initial version.
** 002 CA 20180605 Added program trace in the session view.
** 003 GBB 20231117 Added sessionUuid, relatedSessionUuid, pid, osUser, driverType,
** browserWebSocket, sessionDescription, httpPort. Col width added.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.admin.client.application.home.console.sessions;
import java.util.Date;
import org.gwtbootstrap3.client.ui.Button;
import org.gwtbootstrap3.client.ui.gwt.DataGrid;
import com.goldencode.p2j.admin.*;
import com.goldencode.p2j.admin.client.application.home.BaseViewWithUiHandlers;
import com.goldencode.p2j.admin.client.widget.GridHandle;
import com.goldencode.p2j.admin.client.widget.GridHelper;
import com.goldencode.p2j.admin.client.widget.GridHelper.ColumnInfo;
import com.goldencode.p2j.admin.client.widget.dialog.ModalDialogs;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.i18n.shared.DateTimeFormat;
import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.safehtml.shared.*;
import com.google.gwt.uibinder.client.*;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.inject.*;
/**
* SessionView is a view to manage sessions.
*/
public class SessionView
extends BaseViewWithUiHandlers<SessionUIHandler>
implements SessionPresenter.MyView
{
/**
* GWT UI creator
*/
interface Binder
extends UiBinder<Widget, SessionView>
{}
/** The session table view */
@UiField(provided = true)
DataGrid<SessionInfo> dataGrid = GridHelper.create();
/** The Refresh button */
@UiField
Button refresh;
/** The Filter button */
@UiField
Button filter;
/** The View Program Trace button */
@UiField
Button viewTrace;
/** The Terminate button */
@UiField
Button terminate;
/** Modal container */
@UiField
Widget modalFragment;
/** The Filter Session View */
private final FilterSessionsView filterSessionsView;
/** The Terminate Session Alert */
private final TerminateSessionAlert terminateSessionAlert;
/** Modal dialogs */
private final ModalDialogs dialogs;
/** The grid handle of the session table view */
private final GridHandle<SessionInfo> gridHandle;
/** The session selection model */
private final SingleSelectionModel<SessionInfo> selectionModel;
//private final DateTimeFormat fmt = DateTimeFormat.getFormat("MM/dd/yyyy hh:mm:ss Z, ZZ");
/** The data and time formatter */
private final DateTimeFormat fmt = DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.RFC_2822);
/**
*
*
* @param binder
* The injected GWT UI Binder
* @param dialogs
* The injected ModalDialogs provider
* @param filterSessionsView
* The injected the Filter Session View
* @param terminateSessionAlert
* The injected the Terminate Session Alert
*/
@Inject
SessionView(SessionView.Binder binder,
ModalDialogs dialogs,
FilterSessionsView filterSessionsView,
TerminateSessionAlert terminateSessionAlert)
{
this.dialogs = dialogs;
initWidget(binder.createAndBindUi(this));
ColumnInfo<SessionInfo> col0 = new ColumnInfo<SessionInfo>("Logon Time",
(ri) -> { return fmt.format(new Date(ri.logonTime));},
(r1, r2) -> { return Long.valueOf(r1.logonTime).compareTo(r2.logonTime);});
col0.setWidthInPixels(200);
ColumnInfo<SessionInfo> col1 = new ColumnInfo<SessionInfo>("Account",
(ri) -> {return ri.name;},
(r1, r2) -> { return r1.name.compareTo(r2.name);});
col1.setWidthInPercents(5);
ColumnInfo<SessionInfo> col2 = new ColumnInfo<SessionInfo>("Account Description",
(ri) -> { return ri.descr;},
(r1, r2) -> { return r1.descr.compareTo(r2.descr);});
col2.setWidthInPercents(5);
ColumnInfo<SessionInfo> col3 = new ColumnInfo<SessionInfo>("Account Type",
(ri) -> { return ri.user ? "User" : "Process";},
(r1, r2) -> { return Boolean.valueOf(r1.user).compareTo(r2.user);});
col3.setWidthInPercents(5);
ColumnInfo<SessionInfo> col4 = new ColumnInfo<SessionInfo>("OS User",
(ri) -> {return ri.osUser;},
(r1, r2) -> { return r1.osUser.compareTo(r2.osUser);});
col4.setWidthInPercents(4);
ColumnInfo<SessionInfo> col5 = new ColumnInfo<SessionInfo>("Session Description",
(ri) -> {return ri.sessionDescription;},
(r1, r2) -> { return r1.sessionDescription.compareTo(r2.sessionDescription);});
ColumnInfo<SessionInfo> col6 = new ColumnInfo<SessionInfo>("Session Token ID",
(ri) -> {return String.valueOf(ri.id);},
(r1, r2) -> { return Integer.valueOf(r1.id).compareTo(r2.id);});
col6.setWidthInPercents(4);
ColumnInfo<SessionInfo> col7 = new ColumnInfo<SessionInfo>("Session UUID",
(ri) -> {return ri.uuid;},
(r1, r2) -> { return r1.uuid.compareTo(r2.uuid);});
ColumnInfo<SessionInfo> col8 = new ColumnInfo<SessionInfo>("Related Session UUID",
(ri) -> {return ri.relatedSessionUuid;},
(r1, r2) -> { return r1.relatedSessionUuid.compareTo(r2.relatedSessionUuid);});
ColumnInfo<SessionInfo> col9 = new ColumnInfo<SessionInfo>("Program Trace",
(ri) -> { return buildStackTrace(ri.stacktrace); }, true);
ColumnInfo<SessionInfo> col10 = new ColumnInfo<SessionInfo>("Client Driver",
(ri) -> {return ri.driverType;},
(r1, r2) -> { return r1.driverType.compareTo(r2.driverType);});
ColumnInfo<SessionInfo> col11 = new ColumnInfo<SessionInfo>("Client Web Port",
(ri) -> { return ri.httpPort > 0 ? String.valueOf(ri.httpPort) : "";},
(r1, r2) -> { return Integer.valueOf(r1.httpPort).compareTo(r2.httpPort);});
col11.setWidthInPercents(4);
ColumnInfo<SessionInfo> col12 = new ColumnInfo<SessionInfo>("Client PID",
(ri) -> { return String.valueOf(ri.pid);},
(r1, r2) -> { return Long.valueOf(r1.pid).compareTo(r2.pid);});
col12.setWidthInPercents(4);
ColumnInfo<SessionInfo> col13 = new ColumnInfo<SessionInfo>("Browser Socket",
(ri) -> { return ri.browserWebSocket;},
(r1, r2) -> { return r1.browserWebSocket.compareTo(r2.browserWebSocket);});
col13.setWidthInPercents(5.8);
ColumnInfo<SessionInfo> col14 = new ColumnInfo<SessionInfo>("Client Socket",
(ri) -> { return ri.remoteNet;},
(r1, r2) -> { return r1.remoteNet.compareTo(r2.remoteNet);});
col14.setWidthInPercents(5.8);
ColumnInfo<SessionInfo> col15 = new ColumnInfo<SessionInfo>("Server Socket",
(ri) -> { return String.valueOf(ri.localNet);},
(r1, r2) -> { return r1.localNet.compareTo(r2.localNet);});
col15.setWidthInPercents(5.8);
ColumnInfo<SessionInfo> col16 = new ColumnInfo<SessionInfo>("Secure",
(ri) -> { return ri.secure ? "yes" : "no";},
(r1, r2) -> { return Boolean.valueOf(r1.secure).compareTo(r2.secure);});
col16.setWidthInPercents(3);
ColumnInfo<SessionInfo> col17 = new ColumnInfo<SessionInfo>("Gen #",
(ri) -> { return String.valueOf(ri.cacheGen);},
(r1, r2) -> { return Integer.valueOf(r1.cacheGen).compareTo(r2.cacheGen);});
col17.setWidthInPercents(3);
this.gridHandle = GridHelper.initListGrid(dataGrid, false,
col0, col1, col2,
col3, col4, col5,
col6, col7, col8,
col9, col10, col11,
col12, col13, col14,
col15, col16, col17);
this.selectionModel = (SingleSelectionModel<SessionInfo>) this.gridHandle.getSelectionModel();
this.filterSessionsView = filterSessionsView;
this.terminateSessionAlert = terminateSessionAlert;
setupModalSlot(SessionPresenter.MODAL_CONTENT, modalFragment);
addDialog(filterSessionsView);
addDialog(terminateSessionAlert);
this.viewTrace.setEnabled(false);
this.terminate.setEnabled(false);
this.selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler()
{
@Override
public void onSelectionChange(SelectionChangeEvent event)
{
boolean enabled = SessionView.this.selectionModel.getSelectedObject() != null;
SessionView.this.viewTrace.setEnabled(enabled);
SessionView.this.terminate.setEnabled(enabled);
}
});
}
/**
* Build the HTML representation of these program traces.
*
* @param traces
* The stacktrace information.
*
* @return The GWT {@link SafeHtml} object holding this cell's content.
*/
public static SafeHtml buildStackTrace(StacktraceInfo[] traces)
{
SafeHtmlBuilder html = new SafeHtmlBuilder();
if (traces == null)
{
html.appendHtmlConstant("(no trace available)");
return html.toSafeHtml();
}
// the structure is:
// <b>program1<br/>
// method1(line1 -> line2 -> line3)
// method2(line1 -> line2 -> line3)
// <b>program2<br/>
// method1(line1 -> line2 -> line3)
// method2(line1 -> line2 -> line3)
// ...
String lastProgram = null;
String lastMethod = null;
for (StacktraceInfo trace : traces)
{
if (lastProgram == null || !trace.program.equals(lastProgram))
{
if (lastMethod != null)
{
html.append(')').appendHtmlConstant("<br/>");
}
html.appendHtmlConstant("<b>" + trace.program + "</b><br/>");
lastProgram = trace.program;
lastMethod = null;
}
if (lastMethod == null || !trace.method.equals(lastMethod))
{
if (lastMethod != null)
{
html.append(')').appendHtmlConstant("<br/>");
}
html.appendHtmlConstant(trace.method + "(" + trace.line);
lastMethod = trace.method;
}
else
{
html.appendHtmlConstant(" -> " + trace.line);
}
}
if (lastMethod != null)
{
html.append(')');
}
return html.toSafeHtml();
}
/**
* Sets the session table model.
*
* @param sessions
* The array of sessions
* @param filter
* The filter criteria
*/
@Override
public void setSessions(SessionInfo[] sessions, RegExp filter)
{
gridHandle.clearGrid();
if (sessions == null)
{
return;
}
gridHandle.setRows(sessions, filter);
}
/**
* The Refresh button click handler.
*
* @param e
* Click event
*/
@UiHandler("refresh")
void onRefresh(ClickEvent e)
{
getUiHandlers().updateSessionList();
}
/**
* The View Program Trace button click handler.
*
* @param e
* Click event
*/
@UiHandler("viewTrace")
void onViewTrace(ClickEvent e)
{
SessionInfo row = this.selectionModel.getSelectedObject();
StringBuilder sb = new StringBuilder();
sb.append("<textarea style='height:400px;width:100%'>");
if (row.javaStacktrace == null)
{
sb.append("(no stacktrace available)");
}
else
{
for (String trace : row.javaStacktrace)
{
sb.append(trace);
sb.append("\n");
}
}
sb.append("</textarea>");
dialogs.showInfo("Java Stacktrace", sb.toString(), null);
}
/**
* The Terminate button click handler.
*
* @param e
* Click event
*/
@UiHandler("terminate")
void onTerminate(ClickEvent e)
{
getTerminateSessionAlert().setAlert(this.selectionModel.getSelectedObject());
}
/**
* Gets a reference to the Filter Session View.
*
* @return The Filter Session View
*/
@Override
public FilterSessionsView getFilterView()
{
return this.filterSessionsView;
}
/**
* Gets a reference to the Terminate Session Alert.
*
* @return The Terminate Session Alert
*/
@Override
public TerminateSessionAlert getTerminateSessionAlert()
{
return this.terminateSessionAlert;
}
/**
* Tests if the tested session is selected.
*
* @param session
* The tested session
*
* @return True iff the tested session is selected, otherwise false.
*/
@Override
public boolean isSessionSelected(SessionInfo session)
{
return this.selectionModel.isSelected(session);
}
}