Commit 1df8f331 authored by Florian Fittkau's avatar Florian Fittkau

init

parents
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="con" path="com.google.gwt.eclipse.core.GWT_CONTAINER"/>
<classpathentry kind="output" path="war/WEB-INF/classes"/>
</classpath>
/.gwt
/.gwt-tmp
/build
/build-external
/build-xtend-gen
/build-test
/dist
/gwt-unitCache
/reports
/test-classes
/tomcat
/xtend-gen
/war/gwtmonitoring
/war/WEB-INF/deploy/gwtmonitoring
/war/WEB-INF/classes
Thumbs.db
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>GWTMonitoringExampleWebApp</name>
<comment>GWTMonitoring project</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.google.gdt.eclipse.core.webAppProjectValidator</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.google.gwt.eclipse.core.gwtProjectValidator</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>com.google.gwt.eclipse.core.gwtNature</nature>
</natures>
</projectDescription>
eclipse.preferences.version=1
filesCopiedToWebInfLib=gwt-servlet.jar
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
<stringAttribute key="bad_container_name" value="\GWTMonitoringServerLaunch"/>
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.DevMode"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listEntry value="kieker.monitoring.gwt.GWTMonitoring"/>
</listAttribute>
<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="GWTMonitoring.html"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/GWTMonitoringExampleWebApp"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -startupUrl GWTMonitoring.html -logLevel INFO -codeServerPort 9997 -port 8888 -superDevMode -war C:\Users\Florian\workspace\GWTMonitoringExampleWebApp\war kieker.monitoring.gwt.GWTMonitoring"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="GWTMonitoringExampleWebApp"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx1g"/>
</launchConfiguration>
<?xml version="1.0" encoding="UTF-8"?>
<!--
When updating your version of GWT, you should also update this DTD reference,
so that your app can take advantage of the latest GWT module capabilities.
-->
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.7.0//EN"
"http://gwtproject.org/doctype/2.7.0/gwt-module.dtd">
<module rename-to='gwtmonitoring'>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>
<!-- Inherit the default GWT style sheet. You can change -->
<!-- the theme of your GWT application by uncommenting -->
<!-- any one of the following lines. -->
<inherits name='com.google.gwt.user.theme.clean.Clean'/>
<!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
<!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
<!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> -->
<!-- Other module inherits -->
<!-- Specify the app entry point class. -->
<entry-point class='kieker.monitoring.gwt.client.GWTMonitoring'/>
<!-- Specify the paths for translatable code -->
<source path='client'/>
<source path='shared'/>
<!-- allow Super Dev Mode -->
<add-linker name="xsiframe"/>
</module>
package kieker.monitoring.gwt.client;
import kieker.monitoring.gwt.client.monitoring.MetaMonitoringManager;
import kieker.monitoring.gwt.client.test.TestClass1;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.RootPanel;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class GWTMonitoring implements EntryPoint {
public void onModuleLoad() {
bindButton();
MetaMonitoringManager.init();
}
public void bindButton() {
RootPanel testButton = RootPanel.get("testButton");
testButton.sinkEvents(Event.ONCLICK);
testButton.addHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
TestClass1.testFunction1();
}
}, ClickEvent.getType());
}
}
package kieker.monitoring.gwt.client.monitoring;
public class AspectWeaver {
public static native void weave() /*-{
if (typeof String.prototype.startsWith != 'function') {
String.prototype.startsWith = function(str) {
for (var i = 0; i < str.length; i++) {
if (this[i] != str[i]) {
return false;
}
}
return true;
};
}
$wnd.moduleCacheJSLines = null
$wnd.moduleCacheJSLineLength = 0
$wnd.functionLineMap = {}
$wnd.filenameMap = {}
$wnd.monitoringCache = []
$wnd.lastWrite = 0
$wnd.jQuery.get('http://localhost:9876/gwtmonitoring/' + $strongName
+ '.cache.js', '', function(result) {
$wnd.moduleCacheJSLines = result.split("\n");
$wnd.moduleCacheJSLineLength = $wnd.moduleCacheJSLines.length;
}, 'html');
$wnd.jQuery().readSourceMapURL(
'http://localhost:9876/sourcemaps/gwtmonitoring/' + $strongName
+ '_sourcemap.json');
function aspectInvoc(invocation) {
var toSeekName = 'function ' + invocation.method;
var linenumber = -1;
if (toSeekName in $wnd.functionLineMap) {
linenumber = $wnd.functionLineMap[toSeekName]
} else {
// var firstL1 = $wnd.performance.now()
var toSeekNameLength = toSeekName.length
var lines = $wnd.moduleCacheJSLines
var length = $wnd.moduleCacheJSLineLength
var firstMethodChar = invocation.method[0]
for (var i = 0; i < length; i++) {
var line = lines[i];
if (line.length >= toSeekNameLength
&& line[9] == firstMethodChar
&& line.startsWith(toSeekName)) {
linenumber = i + 1;
$wnd.functionLineMap[toSeekName] = linenumber;
// console.log("lookup of " + toSeekName + " took "
// + ($wnd.performance.now() - firstL1))
break;
}
}
}
if (linenumber == -1)
return invocation.proceed();
var filename = null;
if (linenumber in $wnd.filenameMap) {
filename = $wnd.filenameMap[linenumber]
} else {
// var look1 = $wnd.performance.now()
var filename = $wnd.jQuery().lookupFilename(linenumber)
$wnd.filenameMap[linenumber] = filename
// console.log("filename lookup of " + filename + " took "
// + ($wnd.performance.now() - look1))
}
if (!filename.indexOf("kieker/monitoring/gwt/client") == 0)
return invocation.proceed()
// dont monitor self...
if (filename.indexOf("kieker/monitoring/gwt/client/monitoring") == 0)
return invocation.proceed()
$wnd.monitoringCache.push(filename + ";" + invocation.method + ";" + $wnd.performance.now());
var result = invocation.proceed();
var afterT = $wnd.performance.now();
$wnd.monitoringCache.push(afterT);
if ($wnd.monitoringCache.length >= 1) { // TODO increase for normal use
@kieker.monitoring.gwt.client.monitoring.MetaMonitoringManager::sendRecordBundle(Ljava/lang/String;)($wnd.monitoringCache.toString())
$wnd.monitoringCache = [];
}
// time triggered:
// if (afterT - $wnd.lastWrite > 1000) {
// $wnd.lastWrite = afterT
// @kieker.monitoring.gwt.client.monitoring.MetaMonitoringManager::sendRecordBundle(Ljava/lang/String;)($wnd.monitoringCache.toString())
// $wnd.monitoringCache = [];
// }
return result;
}
$wnd.jQuery.aop
.around(
{
target : this,
method : /(^[a-s].*)|(^[u-z].*)|(^[t][a-x].*)|(^[t][z].*)|(^[t][y][p][e][P].*)|(^[t][y][p][e][_].*)/,
}, aspectInvoc);
}-*/;
}
package kieker.monitoring.gwt.client.monitoring;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
public class MetaMonitoringManager {
private static MetaMonitoringServiceAsync metaMonitoringService;
private static boolean MONITORING_ENABLED = true;
public static void init() {
if (MONITORING_ENABLED) {
metaMonitoringService = createAsyncService();
AspectWeaver.weave();
}
}
private static MetaMonitoringServiceAsync createAsyncService() {
MetaMonitoringServiceAsync metaMonitoringService = GWT.create(MetaMonitoringService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) metaMonitoringService;
String moduleRelativeURL = GWT.getModuleBaseURL() + "metamonitoring";
endpoint.setServiceEntryPoint(moduleRelativeURL);
return metaMonitoringService;
}
public static void sendRecordBundle(String bundle) {
metaMonitoringService.sendRecordBundle(bundle, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
}
@Override
public void onSuccess(Void result) {
}
});
}
}
package kieker.monitoring.gwt.client.monitoring;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
@RemoteServiceRelativePath("metamonitoring")
public interface MetaMonitoringService extends RemoteService {
public void sendRecordBundle(String recordBundle);
}
package kieker.monitoring.gwt.client.monitoring;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface MetaMonitoringServiceAsync {
void sendRecordBundle(String recordBundle, AsyncCallback<Void> callback);
}
package kieker.monitoring.gwt.client.test;
public class TestClass1 {
public static void testFunction1() {
testFunction2();
testFunction2();
}
public static void testFunction2() {
TestClass2.testFunction3();
TestClass2.testFunction3();
}
}
package kieker.monitoring.gwt.client.test;
import com.google.gwt.user.client.ui.RootPanel;
public class TestClass2 {
public static void testFunction3() {
RootPanel testLabel = RootPanel.get("testLabel");
testLabel.setPixelSize(1, 1);
}
}
package kieker.monitoring.gwt.server.monitoring;
import kieker.monitoring.gwt.client.monitoring.MetaMonitoringService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
public class MetaMonitoringServiceImpl extends RemoteServiceServlet implements
MetaMonitoringService {
private static final long serialVersionUID = -1474770740583197159L;
@Override
public void sendRecordBundle(final String recordBundle) {
final String[] splitRecords = recordBundle.split(",");
for (final String record : splitRecords) {
System.out.println(record);
if (record.contains(";")) {
// BEFORE record
final String[] beforeRecordSplit = record.split(";");
String clazzName = beforeRecordSplit[0].substring(0,
beforeRecordSplit[0].lastIndexOf(".") - 1);
clazzName = clazzName.replace("/", ".");
} else {
// AFTER record
}
}
}
}
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link type="text/css" rel="stylesheet" href="css/GWTMonitoring.css">
<title>GWT Web Application Monitoring Example Project</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/aop.js"></script>
<script type="text/javascript" src="js/sourcemap-reading.js"></script>
<script type="text/javascript" src="gwtmonitoring/gwtmonitoring.nocache.js"></script>
</head>
<body>
<noscript>
<div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
Your web browser must have JavaScript enabled
in order for this application to display correctly.
</div>
</noscript>
<h1>GWT Web Application Monitoring Example Project</h1>
<button id="testButton">Call Test Functions</button>
<div id="testLabel"></div>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee">
<servlet>
<servlet-name>MetaMonitoringService</servlet-name>
<servlet-class>kieker.monitoring.gwt.server.monitoring.MetaMonitoringServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MetaMonitoringService</servlet-name>
<url-pattern>/gwtmonitoring/metamonitoring</url-pattern>
</servlet-mapping>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>GWTMonitoring.html</welcome-file>
</welcome-file-list>
</web-app>
/** Add css rules here for your application. */
/** Example rules used by the template application (remove for your app) */
h1 {
font-size: 2em;
font-weight: bold;
color: #777777;
margin: 40px 0px 70px;
text-align: center;
}
.sendButton {
display: block;
font-size: 16pt;
}
/** Most GWT widgets already have a style name defined */
.gwt-DialogBox {
width: 400px;
}
.dialogVPanel {
margin: 5px;
}
.serverResponseLabelError {
color: red;
}
/** Set ids using widget.getElement().setId("idOfElement") */
#closeButton {
margin: 15px 6px 6px;
}
This diff is collapsed.
This diff is collapsed.
// Modified Version of https://github.com/qfox/sourcemapper/blob/master/index.html
( function($) {
jQuery(document).ready(function() {
var SourceMapReader = {
sourcemap: '',
cache: null,
sourceMeta: null,
realOutput: '',
files: [],
filenames: [],
readMapURL: function(mapURL){
SourceMapReader.get(mapURL, function(json){
SourceMapReader.filenames = json.sources;
SourceMapReader.sourcemap = json.mappings;
SourceMapReader.files = [];
// json.sources.forEach(function(source, i){
// SourceMapReader.get(json.sourceRoot + source, function(str){
// files can arrive in any order, but we dont really care about that.
// last one stays on screen until user clicks on a segment in the source.
// SourceMapReader.files[i] = str;
//SourceMapReader.dom.sourcename.innerHTML = ' ('+source+')';
// });
// });
SourceMapReader.cacheMap();
SourceMapReader.sourceMeta = [];
});
},
/**
* Compute the absolute positions of each segment. This eases the lookup times
* at runtime because all segments are relative. That means in order to know the
* position of the very last segment, you need to run through all the previous
* segments first.
* (While this could be delegated to run on-demand, and only up to the point where
* you need it, I chose not to do that for simplicity.)
*
* The data is cached and when the generated source UI is built, the absolute
* values are set as an attribute. After that, the cache is no longer used as
* it will immediately use just that absolute file/col/row value and act accordingly.
*/
cacheMap: function(){
var cache = SourceMapReader.cache = [];
var tcol = 0;
var trow = 0;
var scol = 0;
var srow = 0;
var file = 0;
SourceMapReader.sourcemap.split(';').forEach(function(line,i){
tcol = 0;
line.split(',').forEach(function(str){
var segment = SourceMapReader.decodeSegment(str);
// 0: target col delta, 1: file index, 2: source row delta, 3: source col delta, 4: name index, 5: chunk string
cache.push({
segment: segment,
tcol: tcol+=segment[0]|0,
trow: i,
scol: scol+=segment[3]|0,
srow: srow+=segment[2]|0,
file: file+=segment[1]|0,
});
});
});
},
/**
* Decode given string, which should be a segment in a sourcemap.
* A segment consists of one, four, or five Base64 VLQ encoded
* numbers, which are all delta's, and which are fields of the
* source map.
*
* Base64 is a simple mapping of 0-63 to: A-Za-z0-9+/
*
* VLQ is "variable length quantifier" and deemed an efficient way
* to encode small numbers.
*
* This function will return an array with each field that was
* encountered. The fields are: [target pos, source file index,
* target row, target col, name index]. All fields are delta,
* relative to the previous field (first field offsets at zero).
*
* @param {string} segment
* @return {number[]} One, four, or five fields
*/
decodeSegment: function(segment){
// decode the VLQ encoded segment. 1, 3, or 4 fields
var bytes = this.decodeBase64(segment);
var fields = [];
while (bytes.length) fields.push(SourceMapReader.decodeOneNumberVQL(bytes));
fields[5] = segment; // debug
return fields;
},
/**
* Very straightforward base64 decoder.
*
* @param {string} str
* @return {number[]}
*/
decodeBase64: function(str){
return str.split('').map(function(b){
// each byte is base64 encoded
return 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.indexOf(b);
});
},
/**
* Decode one signed number in a VQL. Will remove used items from
* the input array.
*
* @param {number[]} bytes
* @return {number}
*/
decodeOneNumberVQL: function(bytes){
var num = 0;
var n = 0;
do {
var b = bytes.shift();
num += (b & 31) << (5*n++);
} while (b>>5);
var sign = num & 1;
num >>= 1;
if (sign) num = -num;
return num;
},
get: function(url, func){
jQuery.get(url, func);
},
lookupFilename: function(row){
for (var i = 0; i < SourceMapReader.cache.length; i++) {
var cacheEntry = SourceMapReader.cache[i];
if (cacheEntry.trow == row) {
return SourceMapReader.filenames[cacheEntry.file];
}
};
return null;
},
};
jQuery.fn.readSourceMapURL = function(url) {
SourceMapReader.readMapURL(url);
};
jQuery.fn.lookupFilename = function(row) {
return SourceMapReader.lookupFilename(row);
};
});
} ) ( jQuery );
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment