Share your knowledge
Tuesday, May 10, 2016
A new blog is born
Thursday, May 7, 2015
Switching between maven settings.xml
Often you have to copy the maven settings.xml file which is configured for a specific customer. But while developing in my spare time I just want to use my own settings.xml file. The easiest way to switch to using a different file is shown below:
mvn -gs $M2_HOME/conf/settings_pelssers.xml clean install
Thursday, April 9, 2015
Using ssh tunnel with port forwarding
Connectivity has been setup from our staging environment to the third party server (endpoint of our soap clients). However, I wanted to connect locally with SOAP UI to this server, so I needed to setup an ssh tunnel with portforwarding on my macbook. I used to do this with putty on windows in the past so it took me a bit longer to figure this out.
Let's say the endpoint used from our staging environment would be "http://3rdpartyhostname/coolservice". In this case I want to listen on port 8877, and forward traffic from this port using the ssh tunnel to 3rdpartyhostname on port 80
ssh -f username@staginghostname -L 8877:3rdpartyhostname:80 -N
Now I can connect in SOAPUI to the following endpoint "http://localhost:8877/coolservice"
Thursday, March 26, 2015
Fixing collisions ObjectFactory while executing wsdl2java
Often you have to deal with WSDL's from third parties. Sometimes the WSDL including referenced schemas are setup crappy and you run into issues while converting the WSDL to Java. Below we will look into how to fix these issues.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.pelssers</groupId> | |
<artifactId>objectfactory</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<properties> | |
<cxf.version>2.7.8</cxf.version> | |
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |
</properties> | |
<build> | |
<defaultGoal>clean generate-sources install</defaultGoal> | |
<plugins> | |
<plugin> | |
<groupId>org.apache.cxf</groupId> | |
<artifactId>cxf-codegen-plugin</artifactId> | |
<version>${cxf.version}</version> | |
<executions> | |
<execution> | |
<id>generate-sources</id> | |
<phase>generate-sources</phase> | |
<configuration> | |
<sourceRoot>${project.build.directory}/generated/cxf</sourceRoot> | |
<wsdlOptions> | |
<wsdlOption> | |
<wsdl>${basedir}/src/main/resources/helloworld.wsdl</wsdl> | |
<extraargs> | |
<extraarg>-frontend</extraarg> | |
<extraarg>jaxws21</extraarg> | |
<extraarg>-p</extraarg> | |
<extraarg>http://com.pelssers.helloworld/=com.pelssers.helloworld</extraarg> | |
<extraarg>-p</extraarg> | |
<extraarg>http://com.pelssers.helloworld/wrapper=com.pelssers.helloworld.wrapper</extraarg> | |
<extraarg>-b</extraarg> | |
<extraarg>${basedir}/src/main/resources/bindings.xml</extraarg> | |
</extraargs> | |
</wsdlOption> | |
</wsdlOptions> | |
</configuration> | |
<goals> | |
<goal>wsdl2java</goal> | |
</goals> | |
</execution> | |
</executions> | |
</plugin> | |
</plugins> | |
</build> | |
<dependencies> | |
<dependency> | |
<groupId>org.apache.cxf.xjc-utils</groupId> | |
<artifactId>cxf-xjc-runtime</artifactId> | |
<version>2.6.1</version> | |
</dependency> | |
</dependencies> | |
</project> |
<definitions targetNamespace="http://com.pelssers.helloworld/" | |
name="HelloWorldService" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" | |
xmlns:tns="http://com.pelssers.helloworld/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" | |
xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wrapper="http://com.pelssers.helloworld/wrapper"> | |
<types> | |
<xsd:schema> | |
<xsd:import namespace="http://com.pelssers.helloworld/wrapper" | |
schemaLocation="xsd/helloworld.xsd" /> | |
</xsd:schema> | |
</types> | |
<message name="helloWorldFault"> | |
<part name="fault" element="wrapper:error" /> | |
</message> | |
<message name="helloWorldRequest"> | |
<part name="parameters" element="wrapper:helloWorldRequest"/> | |
</message> | |
<message name="helloWorldResponse"> | |
<part name="parameters" element="wrapper:helloWorldResponse"/> | |
</message> | |
<portType name="HelloWorldService"> | |
<operation name="sayHi"> | |
<input message="tns:helloWorldRequest" /> | |
<output message="tns:helloWorldResponse" /> | |
<fault name="helloWorldFault" message="tns:helloWorldFault" /> | |
</operation> | |
</portType> | |
<binding name="HelloWorldServicePortBinding" type="tns:HelloWorldService"> | |
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> | |
<operation name="sayHi"> | |
<soap:operation soapAction="" /> | |
<input> | |
<soap:body use="literal" /> | |
</input> | |
<output> | |
<soap:body use="literal" /> | |
</output> | |
<fault name="helloWorldFault"> | |
<soap:fault name="helloWorldFault" use="literal" /> | |
</fault> | |
</operation> | |
</binding> | |
<service name="HelloWorldService"> | |
<port name="HelloWorldServicePort" binding="tns:HelloWorldServicePortBinding"> | |
<soap:address location="http://localhost:7001/HelloWorldService" /> | |
</port> | |
</service> | |
</definitions> |
<?xml version='1.0' encoding='UTF-8'?> | |
<xs:schema xmlns:tns="http://com.pelssers.helloworld/wrapper" | |
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" | |
targetNamespace="http://com.pelssers.helloworld/wrapper"> | |
<xs:element name="helloWorldRequest" type="tns:HelloWorldRequestType" /> | |
<xs:element name="helloWorldResponse" type="tns:HelloWorldResponseType" /> | |
<xs:element name="error" type="tns:errorType"/> | |
<xs:element name="unused" type="xs:string"/> | |
<xs:element name="Unused" type="xs:integer"/> | |
<xs:complexType name="HelloWorldRequestType"> | |
<xs:sequence> | |
<xs:element name="firstName" type="xs:string"/> | |
<xs:element name="first_name" type="xs:string"/> | |
<xs:element name="lastName" type="xs:string"/> | |
</xs:sequence> | |
</xs:complexType> | |
<xs:complexType name="HelloWorldResponseType"> | |
<xs:sequence> | |
<xs:element name="greeting" type="xs:string"/> | |
</xs:sequence> | |
</xs:complexType> | |
<xs:complexType name="reasonType"> | |
<xs:simpleContent> | |
<xs:extension base="xs:string" /> | |
</xs:simpleContent> | |
</xs:complexType> | |
<xs:complexType name="ReasonType"> | |
<xs:simpleContent> | |
<xs:extension base="xs:string" /> | |
</xs:simpleContent> | |
</xs:complexType> | |
<xs:complexType name="errorType"> | |
<xs:sequence> | |
<xs:element name="errorCode" type="xs:string"/> | |
<xs:element name="detail" type="xs:string"/> | |
<xs:element name="reason" type="tns:reasonType"/> | |
</xs:sequence> | |
</xs:complexType> | |
</xs:schema> | |
<jaxb:bindings version="2.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" | |
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<jaxb:globalBindings generateElementProperty="false"> | |
<jaxb:javaType name="java.util.Date" xmlType="xsd:dateTime" | |
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDateTime" | |
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDateTime" /> | |
<jaxb:javaType name="java.util.Date" xmlType="xsd:date" | |
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDateTime" | |
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDateTime" /> | |
<jaxb:javaType name="java.util.Date" xmlType="xsd:time" | |
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseTime" | |
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printTime" /> | |
</jaxb:globalBindings> | |
</jaxb:bindings> |
Eclipse will complain with following message
[ERROR] file:/playground/objectfactory/src/main/resources/xsd/helloworld.xsd [32,3]:
(Relevant to above error) another "ReasonType" is generated from here.
[ERROR] file:/playground/objectfactory/src/main/resources/xsd/helloworld.xsd [32,3]:
Two declarations cause a collision in the ObjectFactory class.
[ERROR] file:/playground/objectfactory/src/main/resources/xsd/helloworld.xsd [26,3]:
(Related to above error) This is the other declaration.
[ERROR] file:/playground/objectfactory/src/main/resources/xsd/helloworld.xsd [9,3]:
Two declarations cause a collision in the ObjectFactory class.
[ERROR] file:/playground/objectfactory/src/main/resources/xsd/helloworld.xsd [10,3]:
(Related to above error) This is the other declaration.
[ERROR] file:/playground/objectfactory/src/main/resources/xsd/helloworld.xsd [15,7]:
Two declarations cause a collision in the ObjectFactory class.
[ERROR] file:/playground/objectfactory/src/main/resources/xsd/helloworld.xsd [14,7]:
(Related to above error) This is the other declaration. A class/interface with the same
name "com.pelssers.helloworld.wrapper.ReasonType" is already in use.
Use a class customization to resolve this conflict.
Below a version that fixes all issues. Ps. Sometimes it might also be useful to add @underscoreBinding="asCharInWord" to the globalBindings.
<jaxb:bindings version="2.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" | |
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<jaxb:globalBindings generateElementProperty="false"> | |
<jaxb:javaType name="java.util.Date" xmlType="xsd:dateTime" | |
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDateTime" | |
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDateTime" /> | |
<jaxb:javaType name="java.util.Date" xmlType="xsd:date" | |
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDateTime" | |
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDateTime" /> | |
<jaxb:javaType name="java.util.Date" xmlType="xsd:time" | |
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseTime" | |
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printTime" /> | |
</jaxb:globalBindings> | |
<jaxb:bindings schemaLocation="xsd/helloworld.xsd"> | |
<jaxb:bindings | |
node="//xsd:complexType[@name='HelloWorldRequestType']/xsd:sequence/xsd:element[@name='firstName']"> | |
<jaxb:property name="firstName1" /> | |
</jaxb:bindings> | |
<jaxb:bindings | |
node="//xsd:complexType[@name='HelloWorldRequestType']/xsd:sequence/xsd:element[@name='first_name']"> | |
<jaxb:property name="firstName2" /> | |
</jaxb:bindings> | |
<jaxb:bindings node="//xsd:complexType[@name='reasonType']"> | |
<jaxb:class name="ReasonType1" /> | |
</jaxb:bindings> | |
<jaxb:bindings node="//xsd:complexType[@name='ReasonType']"> | |
<jaxb:class name="ReasonType2" /> | |
</jaxb:bindings> | |
<jaxb:bindings node="xsd:element[@name='unused']"> | |
<jaxb:factoryMethod name="String"/> | |
</jaxb:bindings> | |
<jaxb:bindings node="xsd:element[@name='Unused']"> | |
<jaxb:factoryMethod name="Integer"/> | |
</jaxb:bindings> | |
</jaxb:bindings> | |
</jaxb:bindings> |
Tuesday, April 15, 2014
Javascript promises demo
/** | |
* Check out following URL's | |
* http://www.html5rocks.com/en/tutorials/es6/promises/ | |
* http://www.html5rocks.com/en/tutorials/es6/promises/#toc-async | |
* http://blog.parse.com/2013/01/29/whats-so-great-about-javascript-promises/ | |
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise | |
* | |
* Try this code out on http://repl.it/ | |
* | |
* At present, promises are not yet supported by all browsers and some javascript libraries | |
* offer this functionality already. | |
* | |
* Q seems to be a popular implementation but it's performance seems not that good | |
* https://github.com/kriskowal/q | |
* | |
* Bleubird seems like the most promising implementation in terms of performance | |
* https://github.com/petkaantonov/bluebird | |
* | |
* I hope to find some time soon to prepare a demo with bluebird. | |
***/ | |
function factorial(n) { | |
return new Promise(function(resolve, reject) { | |
if (n < 0) { | |
reject(new Error("n has to be larger than 0!!")); | |
} else { | |
var result = 1; | |
do { | |
result *= n; | |
n--; | |
} | |
while (n > 1); | |
return resolve(result); | |
} | |
}); | |
} | |
function onSucces(result) { | |
console.log("succesfully calculated " + result); | |
} | |
function onError(error) { | |
console.log(error.toString()); | |
} | |
factorial(5).then(onSucces, onError); | |
//succesfully calculated 120 | |
factorial(-3).then(onSucces, onError); | |
//Error: n has to be larger than 0!! |
Little Ajax exercise
Robby Pelssers 37 | |
Valerie Pelssers 7 | |
Lindsey Pelssers 11 |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Ajax demo</title> | |
<script data-main="scripts/ajax" src="scripts/require.js"></script> | |
</head> | |
<body> | |
<h1>This is a demo showing making an AJAX call<h1> | |
<div id="result"/> | |
</body> | |
</html> |
require.config({ | |
baseUrl: 'scripts', | |
paths: { | |
jquery: 'jquery-2.1.0.min' | |
} | |
}); | |
requirejs(["jquery"], function($) { | |
/** | |
0 -> UNSENT | |
1 -> OPENED | |
2 -> HEADERS_RECEIVED | |
3 -> LOADING | |
4 -> DONE | |
**/ | |
function handleStateChange() { | |
var readyState = request.readyState; | |
console.log(readyState); | |
switch(readyState) { | |
case 4: | |
processResponse(request.responseText); | |
break; | |
default: | |
break; | |
} | |
} | |
function nonEmptyString(value) { | |
return value !== ""; | |
} | |
function processResponse(responseText) { | |
console.log("Processing responseText"); | |
var lines = responseText.split('\n'); | |
lines.filter(nonEmptyString).forEach(function(line) { | |
console.log("Processing line: " + line); | |
/** | |
* TODO: dynamically build a table for each line from the CSV file with JQuery | |
* appended as child within <div id="result"/> | |
**/ | |
}); | |
} | |
console.log("About to make Ajax request"); | |
var request = new XMLHttpRequest(); | |
request.open("GET", "data/persons.csv", true); | |
request.onreadystatechange = handleStateChange; | |
request.send(); | |
console.log("Ajax request has been sent"); | |
}); |
Javascript XPath Demo
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Xpath demo</title> | |
<script data-main="scripts/xpath" src="scripts/require.js"></script> | |
</head> | |
<body> | |
<h1>This is a demo showing querying the dom via Xpath<h1> | |
<ul> | |
<li>Javascript</li> | |
<li>Java</li> | |
<li>Scala</li> | |
<li>Ceylon</li> | |
<li>Python</li> | |
</ul> | |
</body> | |
</html> |
/** | |
https://developer.mozilla.org/en-US/docs/Web/XPath | |
**/ | |
requirejs([], function() { | |
//count the number of <li> tags | |
var listItemCount = document.evaluate( 'count(/html/body//li)', document, null, XPathResult.ANY_TYPE, null ); | |
alert("There are " + listItemCount.numberValue + " <li> tags inside the <body> tag"); | |
//output: There are 5 <li> tags inside the <body> tag | |
//stringjoin the values of the <li> nodes | |
var iterator = document.evaluate('/html/body//li', document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); | |
var listItem; | |
var listItemValues = []; | |
while (listItem = iterator.iterateNext()) { | |
listItemValues.push(listItem.textContent); | |
} | |
alert("The languages listed are '" + listItemValues.join() + "'."); | |
//output: The languages listed are 'Javascript,Java,Scala,Ceylon,Python'. | |
}); |
Saturday, April 12, 2014
AngularJS demo
/** | |
* movies.json | |
**/ | |
[ | |
{ | |
"title": "Avatar", | |
"year": 2009, | |
"director": "James Cameron", | |
"actors": ["Sam Worthington", "Sigourney Weaver"] | |
}, | |
{ | |
"title": "Aliens", | |
"year": 1986, | |
"director": "James Cameron", | |
"actors": ["Michael Biehn", "Sigourney Weaver"] | |
}, | |
{ | |
"title": "The Terminator", | |
"year": 1984, | |
"director": "James Cameron", | |
"actors": ["Michael Biehn", "Arnold Schwarzenegger", "Linda Hamilton"] | |
}, | |
{ | |
"title": "Indiana Jones and the Temple of Doom", | |
"year": 1984, | |
"director": "Steven Spielberg", | |
"actors": ["Harrison Ford", "Kate Capshaw"] | |
} | |
] |
<!DOCTYPE html> | |
<html ng-app="moviesApp"> | |
<!-- This demo only works in you serve the files from tomcat or any other webserver --> | |
<head> | |
<title>AngularJS demo</title> | |
<link rel="stylesheet" href="styles/movies.css" type="text/css"/> | |
<script data-main="scripts/movies" src="scripts/require.js"></script> | |
</head> | |
<body ng-controller="moviesController"> | |
<h1>This page is dynamically constructed using AngularJS</h1> | |
<p>Total number of movies is {{movies.length}}</p> | |
<div>Search: <input ng-model="query"></div> | |
<div>Sort by: | |
<select ng-model="orderProp"> | |
<option value="director">director</option> | |
<option value="title">title</option> | |
<option value="year">year</option> | |
</select> | |
</div> | |
<table> | |
<thead> | |
<tr> | |
<th>Title</th> | |
<th>Year</th> | |
<th>Director</th> | |
<th>Actors</th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr ng-repeat="movie in movies | filter:query | orderBy:orderProp"> | |
<td>{{movie.title}}</td> | |
<td>{{movie.year}}</td> | |
<td>{{movie.director}}</td> | |
<td>{{movie.actors.join(",")}}</td> | |
</tr> | |
<tbody> | |
</body> | |
</html> |
/* movies.css */ | |
table { | |
border-collapse:collapse; | |
} | |
th { | |
text-align: left; | |
padding:3px; | |
border: 1px solid red; | |
} | |
td { | |
border: 1px dotted black; | |
padding: 3px; | |
} |
/** | |
* movies.js | |
**/ | |
require.config({ | |
baseUrl: 'scripts', | |
paths: { | |
'angular': 'angular.min' | |
}, | |
shim: { | |
"angular": { | |
exports: "angular" | |
} | |
} | |
}); | |
requirejs(['angular'], function(angular) { | |
var moviesApp = angular.module('moviesApp', []); | |
moviesApp.controller('moviesController', function ($scope, $http) { | |
$http.get('data/movies.json') | |
.success(function(data) { | |
$scope.movies = data; | |
}); | |
$scope.orderProp = 'title'; | |
}); | |
}); |
HTML5 Web Workers demo
<!DOCTYPE html> | |
<html> | |
<!-- This demo only works in you serve the files from tomcat or any other webserver --> | |
<head> | |
<title>Webworker demo</title> | |
<script data-main="scripts/app" src="scripts/require.js"></script> | |
</head> | |
<body> | |
<div><button id="mean">get mean</button></div> | |
<div><button id="max">get max</button></div> | |
</body> | |
</html> |
/** data.js | |
// data generated using http://repl.it/languages/JavaScript | |
var numbers = []; | |
for (var i =0; i < 1000; i++) { | |
numbers.push(Math.round(Math.random() * 1000)); | |
} | |
console.log(JSON.stringify(numbers)); | |
**/ | |
define({ | |
"numbers": [375,797,951,183,732,780,599,597,156,446,156,100,58,459,866,334,601,143,708,651,21,56,970,722,832,939,212,1,182,992,183,617,304,612,525,7,432,23,291,525,612,400,139,47,292,974,366,233,456,91,785,618,200,382,514,983,592,467,46,860,608,680,171,450,65,13,949,942,966,563,808,385,305,16,98,231,684,241,440,683,122,610,495,833,34,173,909,391,259,182,663,755,312,425,520,208,547,568,185,31,970,842,775,450,939,395,895,927,598,727,922,327,88,570,196,521,45,961,325,845,389,747,271,540,829,587,357,965,281,607,543,276,141,296,802,165,75,16,987,423,772,395,199,293,6,14,815,199,707,711,729,790,771,606,74,926,358,651,116,915,863,850,623,449,331,95,64,371,311,669,325,666,730,591,638,275,887,561,472,383,120,972,713,849,761,722,561,236,771,256,494,40,523,711,428,111,25,439,108,202,31,896,636,475,314,563,509,696,908,139,249,604,410,540,756,203,229,943,77,599,290,695,161,880,930,624,808,296,633,105,871,457,804,218,187,417,893,883,539,324,807,122,896,356,318,907,110,272,228,648,427,1,818,353,861,305,7,165,511,534,417,485,222,692,120,269,338,244,943,168,323,219,519,558,703,404,364,65,972,254,962,247,252,696,497,712,301,148,285,998,37,267,610,977,503,411,51,33,279,345,908,634,240,681,145,531,489,448,986,553,242,593,672,81,762,370,238,242,728,803,368,470,632,983,634,399,536,816,90,798,835,151,321,508,187,696,41,858,591,326,678,220,17,711,512,810,226,349,645,96,174,941,691,398,387,518,937,838,138,676,341,735,113,209,925,541,877,696,258,229,660,175,817,982,555,517,530,261,242,996,93,965,897,558,900,883,633,189,339,279,349,700,726,847,897,856,887,405,780,888,642,851,84,936,162,785,899,669,606,581,9,372,101,940,664,974,5,284,161,305,549,486,692,448,652,994,224,176,712,18,237,494,325,179,746,366,650,744,849,721,658,308,568,543,94,509,368,636,265,250,244,590,973,979,393,487,892,906,631,434,795,350,503,645,577,669,493,864,195,230,722,499,281,572,24,769,645,44,177,995,940,470,954,280,915,883,370,748,15,953,928,331,428,553,967,572,964,980,853,75,294,306,385,191,851,268,317,485,169,373,557,395,936,844,696,930,570,70,97,209,615,671,990,359,140,254,518,295,877,323,741,849,697,137,702,709,359,553,294,297,809,420,810,256,867,612,913,82,511,5,502,628,798,194,650,71,702,397,796,51,890,887,338,28,376,579,94,438,578,672,36,328,466,155,543,982,287,839,591,860,31,250,37,39,823,303,360,537,127,327,522,828,770,272,216,965,623,457,85,842,52,194,531,411,541,700,637,138,726,133,976,970,516,715,323,41,795,399,271,434,439,744,78,251,25,184,963,81,836,428,696,688,409,58,173,915,156,442,250,240,549,94,715,183,660,935,280,638,955,517,738,657,554,436,612,730,420,48,248,566,356,159,758,120,14,342,116,92,46,94,41,311,855,980,704,175,474,17,98,763,492,807,473,346,173,465,434,650,399,48,616,949,635,887,45,261,375,15,626,933,503,501,856,539,659,684,163,616,71,944,642,944,27,867,586,636,940,801,575,677,388,573,643,129,458,811,546,821,941,626,386,820,961,651,905,207,196,274,69,215,101,377,18,39,94,618,683,337,71,656,319,385,845,682,23,341,814,261,282,496,118,693,697,348,629,937,877,39,735,418,803,968,282,548,177,423,751,569,807,576,991,732,413,128,372,250,776,581,341,867,931,562,858,239,429,680,751,740,755,238,103,378,903,534,505,497,826,390,320,298,896,100,389,53,11,959,905,847,91,355,319,957,950,677,951,483,573,493,632,83,448,92,293,602,329,554,673,213,752,946,792,781,790,113,91,931,494,974,58,996,550,56,442,737,888,546,351,706,117,969,143,688,762,837,618,867,101,838,84,426,701,223,73,397,822,892,706,147,81,513,85,233,987,581,374,863,371,880,813,237,947,908,986,592,753,350,376,708,84,482,777,378,558,705,424,249,906,330,111,434,493,254,11,405,469,571,56,741,119,767,118,823,649,744,746,681,583,238,962,400,375,478,286,83,869,528,224,436,963,802,12,978,970,556,43,323,891,43,528,925,993,919,74,253,554,695,969,75,523,166,629,217,696,294,455,996,628,697,584,384,901,737,45,915,281,959,950,58,890,395,456,107,620,336,277,170,188,647,464,388,353,229,584,266,78,360,974,260,986,453] | |
}); |
/** mathworker.js **/ | |
function max(numbers) { | |
return Math.max.apply(Math, numbers); | |
} | |
function mean(numbers) { | |
var sum = numbers.reduce(function(acc, num){ return acc + num; }, 0); | |
return sum / numbers.length; | |
} | |
onmessage = function(event) { | |
var message = event.data; | |
var command = message.command; | |
var numbers = message.numbers; | |
switch (command) { | |
case "max": | |
postMessage("The max number is " + max(numbers)); | |
break; | |
case "mean": | |
postMessage("The mean of these numbers is " + mean(numbers)); | |
break; | |
default: | |
postMessage("Unknown command issued!!"); | |
break; | |
} | |
} |
require.config({ | |
baseUrl: 'scripts', | |
paths: { | |
// the left side is the module ID, | |
// the right side is the path to | |
// the jQuery file, relative to baseUrl. | |
// Also, the path should NOT include | |
// the '.js' file extension. This example | |
// is using jQuery 2.1.0 located at | |
// scripts/jquery-2.1.0.min.js, relative to | |
// the HTML page. | |
jquery: 'jquery-2.1.0.min' | |
} | |
}); | |
requirejs(["jquery","./data"], function($, staticdata) { | |
function createMathWorker() { | |
var worker = new Worker("scripts/mathworker.js"); | |
worker.onmessage = function(e) { | |
alert(e.data); | |
} | |
return worker; | |
} | |
function getValue(event) { | |
var numbers = staticdata.numbers; | |
var command = event.data.command; | |
console.log("dispatching calculating " + command + " to worker"); | |
var message = { "command": command, "numbers": numbers}; | |
worker.postMessage(message); | |
} | |
var worker = createMathWorker(); | |
$("#max").on("click", {"command": "max"}, getValue); | |
$("#mean").on("click", {"command": "mean"}, getValue); | |
}); |
Friday, April 11, 2014
Javascript event delegation (bubbling)
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Using event delegation</title> | |
<script src="scripts/matchers.js"></script> | |
<script src="scripts/eventdelegation.js"></script> | |
</head> | |
<body> | |
<div id="item-list"> | |
<div class="item">Item 1</div> | |
<span class="item">Item 2</span> | |
<h3>Item 3</h3> | |
</div> | |
</body> | |
</html> |
/** | |
* matchers.js | |
**/ | |
/***********************************************************/ | |
function Matchers(matchers) { | |
this.matchers = matchers || []; | |
} | |
Matchers.prototype.getMatchers = function() { | |
return this.matchers; | |
} | |
Matchers.prototype.add = function(matcher) { | |
return new Matchers(this.matchers.concat(matcher)); | |
} | |
Matchers.prototype.matches = function(obj) { | |
return this.matchers.every(function(matcher){ | |
return matcher.matches(obj); | |
}); | |
} | |
Matchers.from = function() { | |
var matchers = []; | |
for (var i=0, len=arguments.length; i < len; i++) { | |
matchers.push(arguments[i]); | |
} | |
return new Matchers(matchers); | |
} | |
/***********************************************************/ | |
function AbstractMatcher(predicate) { | |
this.predicate = predicate; | |
} | |
AbstractMatcher.prototype.matches = function(obj) { | |
return this.predicate(obj); | |
} | |
/***********************************************************/ | |
ElementMatcher.prototype.constructor = ElementMatcher; | |
ElementMatcher.prototype = new AbstractMatcher(); | |
function ElementMatcher(predicate) { | |
AbstractMatcher.prototype.constructor.call(this, predicate); | |
} | |
ElementMatcher.byClassName = function(className) { | |
return new ElementMatcher( | |
function(element) { | |
var classes = element.className.split(" "); | |
if (!classes) return false; | |
return classes.indexOf(className) > -1; | |
} | |
); | |
} | |
ElementMatcher.byNodeName = function(nodeName) { | |
return new ElementMatcher( | |
function(element) { | |
return element.nodeName === nodeName.toUpperCase(); | |
} | |
); | |
} | |
/***********************************************************/ |
/** | |
* eventdelegation.js | |
* | |
* Remark: this does not work in IE as I use addEventListener which is not supported by IE. | |
**/ | |
window.onload = (function(){ | |
return function(){ | |
//only place an onclick handler on the parent and let onclick events from the actual | |
//items bubble up to the parent where we handle them | |
document.getElementById("item-list").addEventListener("click", function(event) { | |
var target = event.target; | |
if (Matchers.from(ElementMatcher.byNodeName("div"), ElementMatcher.byClassName("item")).matches(target)) { | |
alert("You clicked on a <div class=\"item\"> with value '" + target.innerHTML + "'"); | |
} else if(ElementMatcher.byClassName("item").matches(target)) { | |
alert("You clicked on a element with class=\"*item*\" with value '" + target.innerHTML + "'"); | |
} else { | |
alert("We are not handling this click event"); | |
} | |
}); | |
}; | |
})(); | |
/** Compare this to JQuery | |
http://api.jquery.com/on/ | |
//attach an onlick handler to each table row | |
$( "#dataTable tbody tr" ).on( "click", function() { | |
alert( $( this ).text() ); | |
}); | |
//attach an onclick handler to the table rows container -> tbody (use event delegation) | |
$( "#dataTable tbody" ).on( "click", "tr", function() { | |
alert( $( this ).text() ); | |
}); | |
**/ |