/*
* 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.xlog.views;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.draw2d.IFigure;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.zest.core.viewers.GraphViewer;
import org.eclipse.zest.core.viewers.IConnectionStyleProvider;
import org.eclipse.zest.core.viewers.IGraphContentProvider;
import org.eclipse.zest.core.widgets.ZestStyles;
import org.eclipse.zest.layouts.LayoutStyles;
import org.eclipse.zest.layouts.algorithms.HorizontalTreeLayoutAlgorithm;
import scouter.client.Images;
import scouter.client.model.AgentDailyListProxy;
import scouter.client.model.AgentObject;
import scouter.client.model.TextProxy;
import scouter.client.model.XLogData;
import scouter.client.net.INetReader;
import scouter.client.net.TcpProxy;
import scouter.client.server.ServerManager;
import scouter.client.util.ColorUtil;
import scouter.client.util.ConsoleProxy;
import scouter.client.util.ExUtil;
import scouter.client.xlog.XLogUtil;
import scouter.client.xlog.actions.OpenXLogProfileJob;
import scouter.lang.pack.MapPack;
import scouter.lang.pack.Pack;
import scouter.lang.pack.XLogPack;
import scouter.io.DataInputX;
import scouter.net.RequestCmd;
import scouter.util.DateUtil;
import scouter.util.FormatUtil;
import scouter.util.Hexa32;
import scouter.util.IPUtil;
import scouter.util.LongEnumer;
import scouter.util.LongKeyLinkedMap;
import scouter.util.LongKeyMap;
public class XLogCallView extends ViewPart {
public static final String ID = XLogCallView.class.getName();
private GraphViewer viewer = null;
private String date;
private long gxid;
private XLogData xlogData;
AgentDailyListProxy agentProxy = new AgentDailyListProxy();
public void createPartControl(Composite parent) {
parent.setLayout(new FillLayout());
parent.addControlListener(new ControlListener() {
public void controlResized(ControlEvent e) {
viewer.applyLayout();
}
public void controlMoved(ControlEvent e) {
}
});
viewer = new GraphViewer(parent, SWT.NONE);
viewer.setContentProvider(new XLogFlowContentProvider());
viewer.setLabelProvider(new XLogFlowLabelProvider());
viewer.setLayoutAlgorithm(new HorizontalTreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
viewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
StructuredSelection sel = (StructuredSelection) event.getSelection();
if (sel.getFirstElement() instanceof XLogConnection) {
XLogData d = ((XLogConnection) sel.getFirstElement()).destXlog;
String date = DateUtil.yyyymmdd(d.p.endTime);
ArrayList<AgentObject> objList = agentProxy.getObjectList(date, d.serverId);
for (AgentObject obj : objList) {
if (obj.getObjHash() == d.p.objHash) {
new OpenXLogProfileJob(XLogCallView.this.getViewSite().getShell().getDisplay(), d, d.serverId).schedule();
break;
}
}
}
}
});
}
public void searchByGxId(String date, long gxId) {
this.date = date;
this.gxid = gxId;
this.setPartName("GxID - " + Hexa32.toString32(gxId));
loadByGxId();
}
public void searchByTxId(XLogData d) {
this.date = DateUtil.yyyymmdd(d.p.endTime);
this.xlogData = d;
loadByTxId();
}
public void setFocus() {
}
private void loadByGxId() {
new LoadGlobalXLog().schedule();
}
private void loadByTxId() {
new LoadChainXLog().schedule();
}
class LoadGlobalXLog extends Job {
public LoadGlobalXLog() {
super("Load " + date);
}
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask("Find " + Hexa32.toString32(gxid), IProgressMonitor.UNKNOWN);
final LongKeyLinkedMap<Object> xlogMap = new LongKeyLinkedMap<Object>();
Iterator<Integer> itr = ServerManager.getInstance().getOpenServerList().iterator();
while (itr.hasNext()) {
final int serverId = itr.next();
monitor.subTask(ServerManager.getInstance().getServer(serverId).getName());
TcpProxy tcp = TcpProxy.getTcpProxy(serverId);
try {
MapPack param = new MapPack();
param.put("date", date);
param.put("gxid", gxid);
tcp.process(RequestCmd.XLOG_READ_BY_GXID, param, new INetReader() {
public void process(DataInputX in) throws IOException {
Pack p = in.readPack();
XLogPack xlog = XLogUtil.toXLogPack(p);
XLogData d = new XLogData(xlog, serverId);
d.objName = TextProxy.object.getLoadText(date, d.p.objHash, d.serverId);
xlogMap.putFirst(xlog.txid, d);
}
});
} catch (Throwable th) {
ConsoleProxy.errorSafe(th.toString());
} finally {
TcpProxy.putTcpProxy(tcp);
}
}
ExUtil.exec(viewer.getGraphControl(), new Runnable() {
public void run() {
viewer.setInput(xlogMap);
}
});
return Status.OK_STATUS;
}
}
class LoadChainXLog extends Job {
public LoadChainXLog() {
super("Load " + date);
}
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask("Find " + Hexa32.toString32(xlogData.p.txid), IProgressMonitor.UNKNOWN);
final LongKeyLinkedMap<XLogData> xlogMap = new LongKeyLinkedMap<XLogData>();
xlogMap.put(xlogData.p.txid, xlogData);
long callerId = xlogData.p.caller;
boolean found = true;
while (found && callerId != 0) {
found = false;
Iterator<Integer> itr = ServerManager.getInstance().getOpenServerList().iterator();
while (itr.hasNext()) {
final int serverId = itr.next();
monitor.subTask(ServerManager.getInstance().getServer(serverId).getName());
TcpProxy tcp = TcpProxy.getTcpProxy(serverId);
try {
MapPack param = new MapPack();
param.put("date", date);
param.put("txid", callerId);
Pack p = tcp.getSingle(RequestCmd.XLOG_READ_BY_TXID, param);
if (p != null) {
XLogPack xlog = XLogUtil.toXLogPack(p);
XLogData d = new XLogData(xlog, serverId);
d.objName = TextProxy.object.getLoadText(date, d.p.objHash, serverId);
xlogMap.put(xlog.txid, d);
callerId = xlog.caller;
found = true;
break;
}
} catch (Throwable th) {
ConsoleProxy.errorSafe(th.toString());
callerId = 0;
} finally {
TcpProxy.putTcpProxy(tcp);
}
}
}
ExUtil.exec(viewer.getGraphControl(), new Runnable() {
public void run() {
viewer.setInput(xlogMap);
}
});
return Status.OK_STATUS;
}
}
class XLogFlowContentProvider implements IGraphContentProvider {
LongKeyLinkedMap<XLogData> xlogMap;
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
if (newInput != null) {
this.xlogMap = (LongKeyLinkedMap<XLogData>) newInput;
}
}
public Object getSource(Object obj) {
if (obj instanceof XLogConnection) {
long key = ((XLogConnection) obj).sourceId;
if (key == 0) {
XLogData d = ((XLogConnection) obj).destXlog;
return new StartHome(IPUtil.toString(d.p.ipaddr));
}
return xlogMap.get(key);
}
return null;
}
public Object getDestination(Object obj) {
if (obj instanceof XLogConnection) {
return ((XLogConnection) obj).destXlog;
}
return null;
}
public Object[] getElements(Object input) {
LongEnumer keys = xlogMap.keys();
ArrayList<XLogConnection> list = new ArrayList<XLogConnection>();
LongKeyMap<Integer> countMap = new LongKeyMap<Integer>();
while (keys.hasMoreElements()) {
long key = keys.nextLong();
XLogData d = xlogMap.get(key);
long caller = d.p.caller;
Integer cntInt = countMap.get(caller);
if (cntInt == null) {
cntInt = new Integer(1);
countMap.put(caller, cntInt);
} else {
cntInt = new Integer(cntInt.intValue() + 1);
countMap.put(caller, cntInt);
}
XLogConnection conn = new XLogConnection(caller, d);
String serviceName = TextProxy.service.getLoadText(DateUtil.yyyymmdd(d.p.endTime), d.p.service, d.serverId);
conn.name = "(" + cntInt.intValue() + ") " + serviceName.substring(serviceName.lastIndexOf("/"), serviceName.length());
conn.elapsed = d.p.elapsed;
conn.error = d.p.error != 0;
list.add(conn);
}
return list.toArray();
}
}
class XLogFlowLabelProvider implements ILabelProvider, IConnectionStyleProvider {
public void addListener(ILabelProviderListener listener) {}
public void dispose() {}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {}
public int getConnectionStyle(Object rel) {
return ZestStyles.CONNECTIONS_DIRECTED;
}
public Color getColor(Object rel) {
if (rel instanceof XLogConnection) {
XLogConnection conn = (XLogConnection) rel;
if (conn.error || conn.elapsed > 8000) {
return ColorUtil.getInstance().getColor(SWT.COLOR_DARK_RED);
}
}
return ColorUtil.getInstance().getColor(SWT.COLOR_DARK_GRAY);
}
public Color getHighlightColor(Object rel) {
return null;
}
public int getLineWidth(Object rel) {
return 0;
}
public IFigure getTooltip(Object entity) {
return null;
}
public Image getImage(Object element) {
if (element instanceof StartHome) {
return Images.CONFIG_USER;
} else if (element instanceof XLogData) {
XLogData d = (XLogData) element;
AgentObject ao = agentProxy.getAgentObject(DateUtil.yyyymmdd(d.p.endTime), d.serverId, d.p.objHash);
if (ao != null) {
return Images.getObjectIcon(ao.getObjType(), true, ao.getServerId());
}
}
return null;
}
public String getText(Object element) {
if (element instanceof XLogData) {
XLogData d = (XLogData) element;
return d.objName;
} else if (element instanceof XLogConnection) {
XLogConnection conn = (XLogConnection) element;
return conn.name + "(" + FormatUtil.print(conn.elapsed, "#,###") + " ms)";
} else if (element instanceof StartHome) {
return ((StartHome) element).ip;
}
return null;
}
}
static class XLogConnection {
long sourceId;
XLogData destXlog;
String name;
long elapsed;
boolean error = false;
XLogConnection(long srcId, XLogData destXlog) {
this.sourceId = srcId;
this.destXlog = destXlog;
}
}
static class StartHome {
String ip;
StartHome(String ip) {
this.ip = ip;
}
}
}