If you're interested in functional programming, you might also want to checkout my second blog which i'm actively working on!!

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!!
view raw gistfile1.js hosted with ❤ by GitHub

Little Ajax exercise

Robby Pelssers 37
Valerie Pelssers 7
Lindsey Pelssers 11
view raw gistfile1.txt hosted with ❤ by GitHub
<!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>
view raw gistfile1.html hosted with ❤ by GitHub
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");
});
view raw gistfile1.js hosted with ❤ by GitHub

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>
view raw gistfile1.html hosted with ❤ by GitHub
/**
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'.
});
view raw gistfile1.js hosted with ❤ by GitHub

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"]
}
]
view raw gistfile1.js hosted with ❤ by GitHub
<!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>
view raw gistfile1.html hosted with ❤ by GitHub
/* movies.css */
table {
border-collapse:collapse;
}
th {
text-align: left;
padding:3px;
border: 1px solid red;
}
td {
border: 1px dotted black;
padding: 3px;
}
view raw gistfile1.css hosted with ❤ by GitHub
/**
* 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';
});
});
view raw gistfile1.js hosted with ❤ by GitHub

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>
view raw gistfile1.html hosted with ❤ by GitHub
/** 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]
});
view raw gistfile1.js hosted with ❤ by GitHub
/** 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;
}
}
view raw gistfile1.js hosted with ❤ by GitHub
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);
});
view raw gistfile1.js hosted with ❤ by GitHub

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>
view raw gistfile1.html hosted with ❤ by GitHub
/**
* 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();
}
);
}
/***********************************************************/
view raw gistfile1.js hosted with ❤ by GitHub
/**
* 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() );
});
**/
view raw gistfile1.js hosted with ❤ by GitHub

Thursday, April 10, 2014

Using HTML5 dataset attributes

<!DOCTYPE html>
<html>
<head>
<title>Using dataset attributes</title>
<script data-main="scripts/dataset" src="scripts/require.js"></script>
</head>
<body>
<!-- any attribute whose name is lowercase and starts with "data-" is considered
a valid HTML5 attribute -->
<span class="circle" data-radius="50" data-title="Circle of life"/>
</body>
</html>
view raw gistfile1.html hosted with ❤ by GitHub
/**
* circle.js
**/
define({
"draw": function(node) {
var dataset = node.dataset;
var radius = parseInt(dataset.radius);
var title = dataset.title;
alert("Drawing circle with title '" + title + "' and radius " + radius);
}
});
/******************************************************************************************************/
/**
* dataset.js
*
* This demo assumes my project looks like
* projectfolder
* - circle.html
* - scripts
* - dataset.js
* - circle.js
**/
requirejs(["./circle"], function(circle) {
//let's draw the circle <span class="circle" data-radius="50"/>
circle.draw(document.querySelector(".circle"));
});
view raw gistfile1.js hosted with ❤ by GitHub

Wednesday, April 9, 2014

Using requirejs as javascript module loader

<!DOCTYPE html>
<html>
<head>
<title>Demo html5 page</title>
<!-- data-main attribute tells require.js to load
scripts/app.js after require.js loads. -->
<script data-main="scripts/app" src="scripts/require.js"></script>
</head>
<body>
<h1>RequireJS demo</h1>
<div><button id="sayHi">Try me!!</button></div>
<div>languages</div>
<ul id="languages"> </ul>
</body>
</html>
view raw gistfile1.html hosted with ❤ by GitHub
/**
* data.js
**/
define({
"programminglanguages": ["Java", "Python","Scala", "Javascript"]
});
view raw gistfile1.js hosted with ❤ by GitHub
/**
* behaviour.js
**/
define({
"sayHi": function() { alert("Hi there :)"); }
});
view raw gistfile1.js hosted with ❤ by GitHub
/**
* app.js
*
* This demo assumes my project looks like
* projectfolder
* - requirejsdemo.html
* - scripts
* - app.js
* - behaviour.js
* - data.js
**/
requirejs(["./behaviour","./data"], function(behaviour, data) {
//for this little demo we will use the plain good ol' DOM API
var languagesEle = document.getElementById("languages");
data.programminglanguages.forEach(
function(language){
//first we create a <li> tag
var li = document.createElement("li");
//next we insert the language into the <li> tag
li.appendChild(document.createTextNode(language));
//we still need to attach the <li> to the existing <ul id="languages">
languagesEle.appendChild(li);
}
);
//we will also add behaviour to the <button id="sayHi">
document.getElementById("sayHi").onclick=behaviour.sayHi;
});
view raw gistfile1.js hosted with ❤ by GitHub

Friday, April 4, 2014

Ceylon: annotations

What is an annotation?

An annotation is a top level function that returns a subtype of ConstrainedAnnotation.

There are 2 interfaces which satisfy ConstrainedAnnotation directly:
  • OptionalAnnotation: An annotation that may occur at most once at a single program element and only on certain program elements.
  • SequencedAnnotation: An annotation that may occur multiple times at a single program element, and only on certain program elements.

Let's see the type hierarchy of ConstrainedAnnotation to get a better picture.


So what you might have thought to be reserved keywords (shared, formal, actual, ...) are in fact annotations used by the compiler.  Let's see how the DocAnnotation is implemented.

"The annotation class for the [[doc]] annotation."
shared final annotation class DocAnnotation(
"Documentation, in Markdown syntax, about the annotated element"
shared String description)
satisfies OptionalAnnotation<DocAnnotation, Annotated> {}
"Annotation to specify API documentation of a program
element."
shared annotation DocAnnotation doc(
"Documentation, in Markdown syntax, about the annotated element"
String description) => DocAnnotation(description);

Wednesday, April 2, 2014

Using Java's FutureTask to execute Callable tasks concurrently

In this demo we have 2 Case Providers, one for Activiti and one for WPS. I used Thread.sleep to mimic a time consuming computation (e.g. IO). Now we want to have a composite Case Provider which composes cases from both case providers. However, as we naively implement this in SequentialCaseProvider we will see that the total time it takes is the sum of having the 2 caseproviders fetch the cases (9 seconds). By using a concurrent approach in ConcurrentCaseProvider, we can reduce the time to +- the time it takes the longest CaseProvider to fetch the cases. (5 seconds)

package com.pelssers.futuretask;
public class Case {
private String message;
public Case(final String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
@Override
public String toString() {
return "Case(" + message + ")";
}
}
view raw gistfile1.java hosted with ❤ by GitHub
package com.pelssers.futuretask;
import java.util.List;
public interface CaseProvider {
List<Case> getCases() throws Exception;
}
view raw gistfile1.java hosted with ❤ by GitHub
package com.pelssers.futuretask;
import java.util.ArrayList;
import java.util.List;
public class ActivitiCaseProvider implements CaseProvider {
private static final List<Case> ACTIVITI_CASES;
static {
ACTIVITI_CASES = new ArrayList<Case>();
ACTIVITI_CASES.add(new Case("ACTIVITI CASE 1"));
ACTIVITI_CASES.add(new Case("ACTIVITI CASE 2"));
ACTIVITI_CASES.add(new Case("ACTIVITI CASE 3"));
}
public List<Case> getCases() throws Exception {
// mimic an expensive operation by sleeping for 4 seconds
Thread.sleep(4000l);
return ACTIVITI_CASES;
}
}
view raw gistfile1.java hosted with ❤ by GitHub
package com.pelssers.futuretask;
import java.util.ArrayList;
import java.util.List;
public class WPSCaseProvider implements CaseProvider {
private static final List<Case> WPS_CASES;
static {
WPS_CASES = new ArrayList<Case>();
WPS_CASES.add(new Case("WPS CASE 1"));
WPS_CASES.add(new Case("WPS CASE 2"));
WPS_CASES.add(new Case("WPS CASE 3"));
}
public List<Case> getCases() throws Exception {
// mimic an expensive operation by sleeping for 5 seconds
Thread.sleep(5000l);
return WPS_CASES;
}
}
view raw gistfile1.java hosted with ❤ by GitHub
package com.pelssers.futuretask;
import java.util.List;
public interface CompositeCaseProvider extends CaseProvider {
void setCaseProviders(final List<CaseProvider> caseProviders);
List<CaseProvider> getCaseProviders();
}
view raw gistfile1.java hosted with ❤ by GitHub
package com.pelssers.futuretask;
import java.util.List;
public abstract class AbstractCompositeCaseProvider implements CompositeCaseProvider {
private List<CaseProvider> caseProviders;
public void setCaseProviders(final List<CaseProvider> caseProviders) {
this.caseProviders = caseProviders;
}
public List<CaseProvider> getCaseProviders() {
return caseProviders;
}
}
view raw gistfile1.java hosted with ❤ by GitHub
package com.pelssers.futuretask;
import java.util.ArrayList;
import java.util.List;
public class SequentialCaseProvider extends AbstractCompositeCaseProvider {
public List<Case> getCases() throws Exception {
final List<Case> cases = new ArrayList<Case>();
for (final CaseProvider caseProvider : getCaseProviders()) {
cases.addAll(caseProvider.getCases());
}
return cases;
}
}
view raw gistfile1.java hosted with ❤ by GitHub
package com.pelssers.futuretask;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public final class ConcurrencyHelper {
public static <T> List<T> getResults(final Iterable<Callable<T>> callables, final int numberOfThreads,
final int sleepInMillis) throws InterruptedException, ExecutionException {
final List<T> results = new ArrayList<T>();
final ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
final List<FutureTask<T>> tasks = mapToFutureTasks(callables);
for (final FutureTask<T> task : tasks) {
executor.execute(task);
}
boolean isFinished = isDone(tasks);
while (!isFinished) {
try {
Thread.sleep(sleepInMillis);
isFinished = isDone(tasks);
} catch (final InterruptedException e) {
}
}
for (final FutureTask<T> task : tasks) {
results.add(task.get());
}
executor.shutdown();
return results;
}
private static <T> List<FutureTask<T>> mapToFutureTasks(final Iterable<Callable<T>> callables) {
final List<FutureTask<T>> futureTasks = new ArrayList<FutureTask<T>>();
for (final Callable<T> callable : callables) {
futureTasks.add(new FutureTask<T>(callable));
}
return futureTasks;
}
private static <T> boolean isDone(final Iterable<FutureTask<T>> tasks) {
final boolean isDone = true;
for (final FutureTask<T> task : tasks) {
if (!task.isDone()) {
return false;
}
}
return isDone;
}
}
view raw gistfile1.java hosted with ❤ by GitHub
package com.pelssers.futuretask;
import java.util.List;
import java.util.concurrent.Callable;
public class CallableCaseProviderAdapter implements Callable<List<Case>> {
private CaseProvider caseProvider;
public CallableCaseProviderAdapter(final CaseProvider caseProvider) {
this.caseProvider = caseProvider;
}
public List<Case> call() throws Exception {
return caseProvider.getCases();
}
}
view raw gistfile1.java hosted with ❤ by GitHub
package com.pelssers.futuretask;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
public class ConcurrentCaseProvider extends AbstractCompositeCaseProvider {
public List<Case> getCases() throws Exception {
final List<Case> result = new ArrayList<Case>();
final int numberOfThreads = 2;
final int sleepInMillis = 300;
final List<List<Case>> casesList = ConcurrencyHelper.getResults(
getCallables(), numberOfThreads, sleepInMillis);
for (final List<Case> cases : casesList) {
result.addAll(cases);
}
return result;
}
public List<Callable<List<Case>>> getCallables() {
final List<Callable<List<Case>>> callables = new ArrayList<Callable<List<Case>>>();
for (final CaseProvider caseProvider : getCaseProviders()) {
callables.add(new CallableCaseProviderAdapter(caseProvider));
}
return callables;
}
}
view raw gistfile1.java hosted with ❤ by GitHub
package com.pelssers.futuretask;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* The output from running main():
*
* Fetching cases using com.pelssers.futuretask.SequentialCaseProvider
* [Case(ACTIVITI CASE 1), Case(ACTIVITI CASE 2), Case(ACTIVITI CASE 3), Case(WPS CASE 1), Case(WPS CASE 2), Case(WPS CASE 3)]
* Fetching cases took 9 seconds
* Fetching cases using com.pelssers.futuretask.ConcurrentCaseProvider
* [Case(ACTIVITI CASE 1), Case(ACTIVITI CASE 2), Case(ACTIVITI CASE 3), Case(WPS CASE 1), Case(WPS CASE 2), Case(WPS CASE 3)]
* Fetching cases took 5 seconds
*/
public class CaseProviderProgram {
public List<CaseProvider> getCaseProviders() {
final List<CaseProvider> caseProviders = new ArrayList<CaseProvider>();
caseProviders.add(new ActivitiCaseProvider());
caseProviders.add(new WPSCaseProvider());
return caseProviders;
}
public CaseProvider getSequentialCaseProvider() {
final CompositeCaseProvider compositeCaseProvider = new SequentialCaseProvider();
compositeCaseProvider.setCaseProviders(getCaseProviders());
return compositeCaseProvider;
}
public CaseProvider getConcurrentCaseProvider() {
final CompositeCaseProvider compositeCaseProvider = new ConcurrentCaseProvider();
compositeCaseProvider.setCaseProviders(getCaseProviders());
return compositeCaseProvider;
}
public static void main(final String[] args) throws Exception {
final CaseProviderProgram program = new CaseProviderProgram();
timeGetCases(program.getSequentialCaseProvider());
timeGetCases(program.getConcurrentCaseProvider());
}
public static void timeGetCases(final CaseProvider caseProvider) throws Exception {
System.out.println("Fetching cases using " + caseProvider.getClass().getName());
// now time how long it takes to fetch all cases using the provided caseProvider
final Date start = new Date();
final List<Case> cases = caseProvider.getCases();
System.out.println(cases);
final Date end = new Date();
final long duration = (end.getTime() - start.getTime()) / 1000;
System.out.println("Fetching cases took " + duration + " seconds");
}
}
view raw gistfile1.java hosted with ❤ by GitHub