| /******************************************************************************* |
| * Copyright (c) 2009, 2015 Xored Software Inc and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Xored Software Inc - initial API and implementation and/or initial documentation |
| *******************************************************************************/ |
| package org.eclipse.rcptt.sherlock.core.reporting; |
| |
| import java.util.Map; |
| |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.EMap; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.ecore.util.EcoreUtil.Copier; |
| import org.eclipse.rcptt.ecl.runtime.BoxedValues; |
| import org.eclipse.rcptt.sherlock.core.INodeBuilder; |
| import org.eclipse.rcptt.sherlock.core.model.sherlock.report.Event; |
| import org.eclipse.rcptt.sherlock.core.model.sherlock.report.EventSource; |
| import org.eclipse.rcptt.sherlock.core.model.sherlock.report.LoggingCategory; |
| import org.eclipse.rcptt.sherlock.core.model.sherlock.report.LoggingData; |
| import org.eclipse.rcptt.sherlock.core.model.sherlock.report.Node; |
| import org.eclipse.rcptt.sherlock.core.model.sherlock.report.Report; |
| import org.eclipse.rcptt.sherlock.core.model.sherlock.report.ReportBuilderStore; |
| import org.eclipse.rcptt.sherlock.core.model.sherlock.report.ReportFactory; |
| import org.eclipse.rcptt.sherlock.core.model.sherlock.report.Snaphot; |
| |
| /** |
| * Build a complex report. |
| */ |
| public class ReportBuilder implements IReportBuilder { |
| private static final String NODE_INDEX_PROPERTY = "rcptt.watson.node.index"; |
| private static final String NODE_LASTSTARTTIME_PROPERTY = "rcptt.watson.node.last-start-time"; |
| |
| private final Report report; |
| private NodeBuilder currentNode; |
| |
| //Provides synchronized access to report nodes |
| private class NodeBuilder implements INodeBuilder { |
| private final Node node; |
| private NodeBuilder parent; |
| private int currentChildIndex = 0; |
| |
| private NodeBuilder(NodeBuilder parent, Node node){ |
| if (parent == null) { |
| EObject container = node.eContainer(); |
| if (container instanceof Node) { |
| parent = new NodeBuilder(null, (Node) container); |
| } |
| } |
| this.parent = parent; |
| this.node = node; |
| } |
| |
| /** |
| * Will add new node to current one and go one level down. |
| */ |
| @Override |
| public INodeBuilder beginTask(String name) { |
| NodeBuilder childNode = findChildNode(name); |
| if (childNode != null) { |
| return childNode; |
| } |
| Node child = ReportFactory.eINSTANCE.createNode(); |
| child.setName(name); |
| child.setStartTime(getTime()); |
| setNodeIndex(child, currentChildIndex); |
| setNodeLastStartTime(child, child.getStartTime()); |
| synchronized (report) { |
| node.getChildren().add(getChildPosition(name), child); |
| currentNode = new NodeBuilder(this, child); |
| } |
| currentChildIndex++; |
| return currentNode; |
| } |
| |
| private NodeBuilder findChildNode(String name) { |
| for (Node child : node.getChildren()) { |
| if (name.equals(child.getName()) |
| && currentChildIndex == getNodeIndex(child)) { |
| setNodeLastStartTime(child, getTime()); |
| synchronized (report) { |
| currentNode = new NodeBuilder(this, child); |
| } |
| currentChildIndex++; |
| return currentNode; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Find existing subnode by name and index and make it active. |
| */ |
| public INodeBuilder appendTask(String name) { |
| for (Node child : node.getChildren()) { |
| if (name.equals(child.getName())) { |
| setNodeLastStartTime(child, getTime()); |
| synchronized (report) { |
| currentNode = new NodeBuilder(this, child); |
| } |
| return currentNode; |
| } |
| } |
| return beginTask(name); |
| } |
| |
| /** |
| * Will go one level up. |
| */ |
| @Override |
| public void endTask() { |
| synchronized (report) { |
| node.setEndTime(getTime()); |
| long duration = node.getEndTime() - getNodeLastStartTime(node); |
| node.setDuration(node.getDuration() + duration); |
| if (parent == null) |
| throw new IllegalStateException("Root report node can't be closed."); |
| currentNode = parent; |
| } |
| } |
| |
| @Override |
| public void createEvent(Event event) { |
| synchronized (report) { |
| Event childEvent = findChildEvent(event); |
| if (childEvent != null) { |
| childEvent.setCount(childEvent.getCount() + 1); |
| return; |
| } |
| Event copy = EcoreUtil.copy(event); |
| copy.setTime(getTime()); |
| node.getEvents().add(copy); |
| } |
| } |
| |
| private Event findChildEvent(Event event) { |
| for (Event childEvent : node.getEvents()) { |
| if (EcoreUtil.equals(event.getData(), childEvent.getData())) { |
| return childEvent; |
| } |
| } |
| return null; |
| } |
| |
| /* |
| * Add or append existing log entry into current node. |
| */ |
| @Override |
| public void appendLog(LoggingCategory category, String text) { |
| String log_key = getLogCategoryKey(category); |
| synchronized (report) { |
| EMap<String, EObject> properties = node.getProperties(); |
| LoggingData data = (LoggingData) properties.get(log_key); |
| if (data == null) |
| properties.put(log_key, data = ReportFactory.eINSTANCE.createLoggingData()); |
| StringBuilder sb = new StringBuilder(data.getText()); |
| sb.append(text); |
| sb.append("\n"); |
| data.setText(sb.toString()); |
| } |
| } |
| |
| @Override |
| public void setProperty(String key, EObject value) { |
| EObject copy = EcoreUtil.copy(value); |
| synchronized (report) { |
| node.getProperties().put(key, copy); |
| } |
| } |
| |
| @Override |
| public EObject getProperty(String key) { |
| synchronized (report) { |
| return node.getProperties().get(key); |
| } |
| } |
| |
| @Override |
| public NodeBuilder getParent() { |
| return parent; |
| } |
| |
| @Override |
| public void addSnapshot(Snaphot snapshot) { |
| Snaphot copy = EcoreUtil.copy(snapshot); |
| copy.setTime(getTime()); |
| synchronized (report) { |
| node.getSnapshots().add(copy); |
| } |
| } |
| |
| @Override |
| public void update(Procedure1<Node> runnable) { |
| synchronized (report) { |
| runnable.apply(node); |
| } |
| } |
| |
| @Override |
| public String getName() { |
| return node.getName(); |
| } |
| |
| @Override |
| public String toString() { |
| return node.getName(); |
| } |
| |
| private int getChildPosition(String name) { |
| int position = -1; |
| int size = node.getChildren().size(); |
| for (int i = 0; i < size; i++) { |
| Node child = node.getChildren().get(i); |
| if (currentChildIndex == getNodeIndex(child)) { |
| position = i; |
| } |
| } |
| return position == -1 ? size : (position + 1); |
| } |
| |
| } |
| |
| static private Report createReport() { |
| Report report = ReportFactory.eINSTANCE.createReport(); |
| Node root = ReportFactory.eINSTANCE.createNode(); |
| report.setRoot(root); |
| root.setName("root"); |
| root.setStartTime(getTime()); |
| return report; |
| } |
| |
| private ReportBuilder(Report report, Node currentNode) { |
| this.report = report; |
| this.currentNode = new NodeBuilder(null, currentNode); |
| if (report.getRoot() == null) |
| throw new NullPointerException(); |
| if (currentNode == null) |
| throw new NullPointerException(); |
| Node root = currentNode; |
| |
| while (root.getParent() != null) |
| root = root.getParent(); |
| if (root != report.getRoot()) |
| throw new IllegalArgumentException(); |
| } |
| |
| public EventSource registerEventSource(String name) { |
| EventSource source = ReportFactory.eINSTANCE.createEventSource(); |
| source.setName(name); |
| synchronized (report) { |
| report.getSources().add(source); |
| } |
| return source; |
| } |
| |
| |
| // @Override |
| // public void withCurrentNode(Procedure1<Node> procedure) { |
| // synchronized (report) { |
| // procedure.apply(currentNode); |
| // } |
| // } |
| |
| // Report getReport() { |
| // synchronized (report) { |
| // report.getRoot().setEndTime(getTime()); |
| // } |
| // return report; |
| // } |
| |
| public Report getReportCopy() { |
| synchronized (report) { |
| Report reportCopy = EcoreUtil.copy(report); |
| Node root = reportCopy.getRoot(); |
| root.setEndTime(getTime()); |
| root.setDuration(root.getEndTime() - root.getStartTime()); |
| return reportCopy; |
| } |
| } |
| |
| @Override |
| public INodeBuilder getCurrent() { |
| return currentNode; |
| } |
| |
| public static long getTime() { |
| return System.currentTimeMillis(); |
| } |
| |
| public void registerProviders(String... id) { |
| if (id.length == 0) { |
| EventProviderManager.getInstance().register(this, null); |
| } else { |
| for (String lid : id) { |
| EventProviderManager.getInstance().register(this, lid); |
| } |
| } |
| } |
| |
| public void unregisterProviders(String... id) { |
| if (id.length == 0) { |
| EventProviderManager.getInstance().unregister(this, null); |
| } else { |
| for (String lid : id) { |
| EventProviderManager.getInstance().unregister(this, lid); |
| } |
| } |
| } |
| |
| /** |
| * Search for event source with equals eobject specified in property |
| */ |
| public EventSource findSource(String attr, EObject info) { |
| synchronized (report) { |
| EList<EventSource> sources = report.getSources(); |
| for (EventSource eventSource : sources) { |
| EObject object = eventSource.getProperties().get(attr); |
| if (object != null && EcoreUtil.equals(object, info)) { |
| return eventSource; |
| } |
| } |
| } |
| return null; |
| } |
| |
| |
| private static String getLogCategoryKey(LoggingCategory category) { |
| return "log_" + category.name(); |
| } |
| |
| public static String getLogs(Node node) { |
| StringBuilder result = new StringBuilder(); |
| String logs = null; |
| for (LoggingCategory cat : LoggingCategory.VALUES) { |
| logs = getLogs(node, cat); |
| if (logs != null) { |
| result.append(logs); |
| } |
| } |
| return result.toString(); |
| } |
| public static String getLogs(Node node, LoggingCategory cat) { |
| EObject object = node.getProperties().get(getLogCategoryKey(cat)); |
| if (object != null && object instanceof LoggingData) { |
| return ((LoggingData) object).getText(); |
| } |
| return null; |
| } |
| |
| |
| public static ReportBuilder create(String title) { |
| Report report = createReport(); |
| report.getRoot().setName(title); |
| return new ReportBuilder(report, report.getRoot()); |
| } |
| |
| public ReportBuilderStore save() { |
| ReportBuilderStore store = ReportFactory.eINSTANCE.createReportBuilderStore(); |
| synchronized (report) { |
| EcoreUtil.Copier copier = new Copier(); |
| store.setReport((Report) copier.copy(report)); |
| store.setCurrentNode((Node) copier.get(currentNode.node)); |
| } |
| assert store.getCurrentNode() != null; |
| assert store.getCurrentNode().eContainer() != null; |
| Node root = store.getReport().getRoot(); |
| root.setEndTime(getTime()); |
| root.setDuration(root.getEndTime() - root.getStartTime()); |
| return store; |
| } |
| |
| public static ReportBuilder load(ReportBuilderStore store) { |
| return new ReportBuilder(store.getReport(), store.getCurrentNode()); |
| } |
| |
| public static Snaphot createSnapshot(EObject data, Map<String, EObject> properties) { |
| Snaphot snapshot = ReportFactory.eINSTANCE.createSnaphot(); |
| snapshot.setTime(getTime()); |
| snapshot.setData(data); |
| if (properties != null) { |
| snapshot.getProperties().addAll(properties.entrySet()); |
| } |
| return snapshot; |
| } |
| |
| private static int getNodeIndex(Node node) { |
| Object index = BoxedValues.unbox(node.getProperties().get(NODE_INDEX_PROPERTY)); |
| assert index != null; |
| assert index instanceof Integer; |
| return ((Integer) index).intValue(); |
| } |
| |
| private static void setNodeIndex(Node node, int index) { |
| node.getProperties().put(NODE_INDEX_PROPERTY, BoxedValues.box(index)); |
| } |
| |
| private static long getNodeLastStartTime(Node node) { |
| Object index = BoxedValues.unbox(node.getProperties().get(NODE_LASTSTARTTIME_PROPERTY)); |
| assert index != null; |
| assert index instanceof Long; |
| return ((Long) index).longValue(); |
| } |
| |
| private static void setNodeLastStartTime(Node node, long startTime) { |
| node.getProperties().put(NODE_LASTSTARTTIME_PROPERTY, BoxedValues.box(startTime)); |
| } |
| |
| } |