/*
* Copyright 2015 the original author or authors.
* @https://github.com/scouter-project/scouter
*
* 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 scouter.client.views;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import scouter.client.Images;
import scouter.client.model.AgentDataProxy;
import scouter.client.net.TcpProxy;
import scouter.client.popup.EditableMessageDialog;
import scouter.client.server.GroupPolicyConstants;
import scouter.client.server.ServerManager;
import scouter.client.util.*;
import scouter.client.util.UIUtil.ViewWithTable;
import scouter.lang.pack.MapPack;
import scouter.lang.value.*;
import scouter.net.RequestCmd;
import scouter.util.CastUtil;
import scouter.util.FormatUtil;
import java.util.ArrayList;
public class ObjectThreadDetailView extends ViewPart implements ViewWithTable{
public static final String ID = ObjectThreadDetailView.class.getName();
private int objHash;
private long threadid;
private long txid;
private int serverId;
private ArrayList<ColoringWord> defaultHighlightings;
CustomLineStyleListener listener;
Button interruptBtn, stopBtn, resumeBtn, suspendBtn;
public void init(IViewSite site) throws PartInitException {
super.init(site);
String secId = site.getSecondaryId();
String[] ids = secId.split("&");
serverId = Integer.valueOf(ids[0]);
objHash = Integer.valueOf(ids[1]);
}
public void initializeColoring(){
defaultHighlightings = new ArrayList<ColoringWord>();
defaultHighlightings.add(new ColoringWord("javax.servlet.http.HttpServlet", SWT.COLOR_BLUE, false));
defaultHighlightings.add(new ColoringWord("org.apache.jasper.servlet.JspServlet", SWT.COLOR_BLUE, false));
defaultHighlightings.add(new ColoringWord("java.lang.Thread.sleep", SWT.COLOR_RED, false));
defaultHighlightings.add(new ColoringWord("java.lang", SWT.COLOR_BLUE, false));
defaultHighlightings.add(new ColoringWord("java.util", SWT.COLOR_BLUE, false));
}
public void createPartControl(final Composite parent) {
initializeColoring();
SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
sashForm.SASH_WIDTH = 1;
Composite composite = new Composite(sashForm, SWT.NONE);
composite.setLayout(new GridLayout(1, true));
Composite upperComp = new Composite(composite, SWT.NONE);
upperComp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
upperComp.setLayout(UIUtil.formLayout(3, 3));
if (ServerManager.getInstance().getServer(serverId).isAllowAction(GroupPolicyConstants.ALLOW_KILLTRANSACTION)) {
resumeBtn = new Button(upperComp, SWT.PUSH);
resumeBtn.setText("&Resume");
resumeBtn.setImage(Images.WARN);
resumeBtn.setLayoutData(UIUtil.formData(null, -1, null, -1, 100, -5, null, -1, 100));
resumeBtn.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (MessageDialog.openConfirm(parent.getShell(), "Resume Thread", "This thread will be resumed.(This may result in throwing a SecurityException) Continue?")) {
controlThread("resume");
}
}
});
suspendBtn = new Button(upperComp, SWT.PUSH);
suspendBtn.setText("&Suspend");
suspendBtn.setImage(Images.WARN);
suspendBtn.setLayoutData(UIUtil.formData(null, -1, null, -1, resumeBtn, -5, null, -1, 100));
suspendBtn.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (MessageDialog.openConfirm(parent.getShell(), "Suspend Thread", "This thread will be suspended.(This may result in throwing a SecurityException) Continue?")) {
controlThread("suspend");
}
}
});
stopBtn = new Button(upperComp, SWT.PUSH);
stopBtn.setText("&Stop");
stopBtn.setImage(Images.WARN);
stopBtn.setLayoutData(UIUtil.formData(null, -1, null, -1, suspendBtn, -5, null, -1, 100));
stopBtn.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (MessageDialog.openConfirm(parent.getShell(), "Stop Thread", "This thread will be terminated.(This feature requires a pre-test) Continue?")) {
controlThread("stop");
}
}
});
interruptBtn = new Button(upperComp, SWT.PUSH);
interruptBtn.setText("&Interrupt");
interruptBtn.setLayoutData(UIUtil.formData(null, -1, null, -1, stopBtn, -5, null, -1, 100));
interruptBtn.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (MessageDialog.openConfirm(parent.getShell(), "Interrupt Thread", "This thread will be interrupted. Continue?")) {
controlThread("interrupt");
}
}
});
}
table = build(composite);
table.addMouseListener(new MouseAdapter() {
public void mouseDoubleClick(MouseEvent e) {
TableItem[] items = table.getSelection();
if (items == null || items.length < 1) {
return;
}
String key = items[0].getText(0);
String content = items[0].getText(1);
new EditableMessageDialog().show(key, content);
}
});
table.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (e.keyCode == SWT.F5) {
reload();
}
}
});
stacktrace = new StyledText(sashForm, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
stacktrace.setText("");
stacktrace.setFont(new Font(null, "verdana", 10, 0));
stacktrace.setMargins(10, 10, 10, 10);
listener = new CustomLineStyleListener(false, defaultHighlightings, false);
stacktrace.addLineStyleListener(listener);
IToolBarManager man = getViewSite().getActionBars().getToolBarManager();
man.add(new Action("reload",ImageUtil.getImageDescriptor(Images.refresh)) {
public void run() {
reload();
}
});
}
public void setInput(long threadId, long txid) {
this.threadid = threadId;
this.txid = txid;
if(threadId != 0L) {
this.setPartName("Thread Detail[" + threadid + "]");
} else {
this.setPartName("Deferred Tx Detail[" + txid + "]");
}
table.removeAll();
stacktrace.setText("");
reload();
}
protected Table table;
protected StyledText stacktrace;
private Table build(Composite parent) {
table = new Table(parent, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL);
table.setLayoutData(new GridData(GridData.FILL_BOTH));
table.setHeaderVisible(true);
table.setLinesVisible(true);
TableColumn[] cols = new TableColumn[9];
cols[0] = UIUtil.create(table, SWT.LEFT, "Key", cols.length, 0, true, 150, this);
cols[1] = UIUtil.create(table, SWT.NONE, "Value", cols.length, 1, true, 600, this);
return table;
}
protected void reload() {
ExUtil.asyncRun(new Runnable() {
public void run() {
final MapPack mp = AgentDataProxy.getThreadDetail(objHash, threadid, txid, serverId);
setThreadDetailContens(mp);
}
});
}
private void setThreadDetailContens (final MapPack pack) {
ExUtil.exec(table, new Runnable() {
public void run() {
table.removeAll();
stacktrace.setText("");
int time = CastUtil.cint(pack.get("Service Elapsed"));
boolean serviceThread = false;
String[] names = scouter.util.SortUtil.sort_string(pack.keys(), pack.size());
for (int i = 0, j = 0; i < names.length; i++) {
String key = names[i];
Value value = pack.get(key);
if ("Stack Trace".equals(key)) {
stacktrace.setText(CastUtil.cString(value));
continue;
}
String text = null;
TableItem ti = new TableItem(table, SWT.NONE, j++);
if (value instanceof TextValue) {
text = CastUtil.cString(value);
ti.setText(0, key);
ti.setText(1, text);
} else {
if (value instanceof DecimalValue) {
text = FormatUtil.print(value, "#,##0");
} else if (value instanceof DoubleValue || value instanceof FloatValue) {
text = FormatUtil.print(value, "#,##0.0##");
}
ti.setText(new String[] { key, text });
}
if (key.startsWith("Service")) {
if (time > 8000) {
ti.setForeground(ColorUtil.getInstance().getColor(SWT.COLOR_RED));
} else if (time > 3000) {
ti.setForeground(ColorUtil.getInstance().getColor(SWT.COLOR_MAGENTA));
} else {
ti.setForeground(ColorUtil.getInstance().getColor(SWT.COLOR_BLUE));
}
serviceThread = true;
}
}
if (stopBtn != null && interruptBtn != null) {
stopBtn.setEnabled(serviceThread);
interruptBtn.setEnabled(serviceThread);
resumeBtn.setEnabled(serviceThread);
suspendBtn.setEnabled(serviceThread);
}
sortTable();
}
});
}
private void controlThread(final String action) {
ExUtil.asyncRun(new Runnable() {
public void run() {
TcpProxy tcp = TcpProxy.getTcpProxy(serverId);
MapPack p = null;
try {
MapPack param = new MapPack();
param.put("objHash", objHash);
param.put("id", threadid);
param.put("action", action);
p = (MapPack) tcp.getSingle(RequestCmd.OBJECT_THREAD_CONTROL, param);
} catch (Exception e) {
e.printStackTrace();
} finally {
TcpProxy.putTcpProxy(tcp);
}
if (p != null) {
setThreadDetailContens(p);
}
}
});
}
public void setFocus() {
}
@Override
public void dispose() {
super.dispose();
}
boolean asc;
int col_idx;
boolean isNum;
public void setSortCriteria(boolean asc, int col_idx, boolean isNum) {
this.asc = asc;
this.col_idx = col_idx;
this.isNum = isNum;
}
public void setTableItem(TableItem t) {
}
public void sortTable(){
int col_count = table.getColumnCount();
TableItem[] items = table.getItems();
if (isNum) {
new SortUtil(asc).sort_num(items, col_idx, col_count);
} else {
new SortUtil(asc).sort_str(items, col_idx, col_count);
}
}
}