Java Web Application sending JSON messages through WebSocket to HTML5 browser application for real time push

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

imageThis article describes a Java EE 7 web application that exposes a REST service that handles HTTP POST requests with JSON payload. Any message received is sent through a Web Socket to the web socket (server) endpoint that is published by a Java Class deployed as part of the web application. A static HTML page with two associated JavaScript libraries is opened in a web browser and has opened a web socket connection to this same end point. The message sent from the REST service endpoint to the web socket endpoint is pushed through the web socket to the browser and used to instantly update the web page.

The specific use case that is implemented is a simple web dashboard to monitor a movie theater: the current number of people in each of the four rooms of this movie theater is observed. The REST service receives the actual spectator count and through the two web socket interactions, this count ends up in the browser and in the visual presentation.

Below you will find a step by step instruction for implementing this use case including all required source code. The implementation uses only standard technologies: Java EE 7 (including JAX-RS and Web Socket ) and plain HTML5 and JavaScript – no special libraries are involved. The code is developed in Oracle JDeveloper (12c) and deployed to Oracle WebLogic  (12c). However, given that only standard components are used, the same code should work equally well on other containers and from other IDEs.

Note: for the use case presented in this article, a somewhat simpler solution would be possible using Server Sent Events (SSE) – a simpler and lighter weight approach than the use of web sockets. SSE is uni-directional (server to client push only) and that of course is exactly what I am doing in this particular example.

The steps will be:

  • Implement the REST service to handle json payloads in HTTP Post requests
  • Implement the WebSocket endpoint
  • Interact from REST service endpoint with WebSocket (endpoint)
  • Implement the HTML and JavaScript web application to present the live status for the movie theater based on the web socket messages

The starting point is a basic Java EE web application – with no special setup in web.xml or other files.

The final application looks like this:

image

For JDeveloper 12c users: the required libraries are JAX-RS Jersey Jettison (Bundled), JAX-RS Jersey 2.x, WebSocket, Servlet Runtime.

Implement the REST service to handle json payloads in HTTP Post requests

Publishing a REST service from Java (EE) is done using JAX-RS. In an earlier post, I described how to expose a REST service from Java SE (out of Java EE containers, leveraging the HTTP Server in the JVM). Publishing from within a Java EE container is very similar – and even easier. All we need is a single class with the right annotations.

image

The class is shown below. It is called MovieEvent (although the Class name does not matter at all). The class is annotated with the @Path annotation that is part of the JAX-RS specification. Because of this annotation, the class is published as a REST resource. The string parameter in this annotation (“cinemaevent”) defines the resource name as used in the URL for this REST service. The entire URL where this service can be invoked will be http://host:port/<web application root>/resources/cinemaevent. Note the segment resources that comes between the web application root and the name of the resource. That one had me confused for some time. The web application root for this application is set to CinemaMonitor by the way.

package nl.amis.cinema.view;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Request;

//invoke at : http://localhost:7101/CinemaMonitor/resources/cinemaevent
@Path("cinemaevent")
public class MovieEvent {

public MovieEvent() {
}

@POST
@Consumes("application/json")
@Produces("text/plain")
public String postMovieEvent(@Context Request request, String json) {
System.out.println("received event:" + json);
return "event received " + json;
}

@GET
@Produces("text/plain")
public String getMovieEvent(@Context Request request) {
return "nothing to report from getMovieEvent";
}
}

Method postMovieEvent is annotated with @POST – making it the handler of POST requests sent to the REST resource (at the URL discussed above). However, the annotation @Consumes(“application/json”) ensures that only HTTP requests with their content-type appropriately set to application/json will indeed be delivered to this method. The JSON payload of these requests is passed in the json input parameter. Note that not its name is relevant but the fact that it is the first String input parameter to this method without special annotations such as @Context.

At the present, the method does nothing useful – it write the JSON payload to the system output and returns a fairly bland confirmation message. Before too long, we will extend both this method and the entire class to interact with the web socket.

The REST service can be tested, for example from SoapUI or a Java client program by sending requests such as this one:

image

The corresponding output in the console (from the running Java EE container):

image

Implement the WebSocket endpoint

Implementing a WebSocket endpoint in Java EE is defined through the JSR-356 specification. A very good overview of how to use web sockets in Java applications is provided in this article.

Turning a Java Class into a WebSocket endpoint is actually quite simple. Use a few annotations, and we are in business. It is important to realize that even though the class that acts as the Web Socket server (endpoint) is deployed in this case as part of a Java EE web application, it stands quite apart from the rest of that application. The web socket endpoint can be accessed, not just from browsers but from Java clients as well. But there is no instance of the Class that is accessible for direct Java calls, nor does the WebSocket endpoint hook into EJBs, JMS destinations or JSF managed beans. It is a rather isolated component within the Java EE application. It does however have the potential to consume CDI Events (as described by Bruno Borges in this excellent article that inspired me to write this piece).

Create a Class called CinemaEventSocketMediator. Add the following annotation: @ServerEndpoint(“/cinemaSocket/{client-id}”). This turns the class into a web socket endpoint that exposes a Web Socket [channel]at ws://host:port/<web application context root>/cinemaSocket (in this case that will be ws://localhost:7101/CinemaMonitor/cinemaSocket). The final segment of the URL (/{client-id}) introduces a path parameter. The address of the Web Socket ends with the segment cinemaSocket. Anything that is added behind it is interpreted as an additional parameter that can be leveraged in the onOpen, onClose and onMessage methods through the @PathParam annotation – as we will see next.

A collection of peers is defined in which each client that starts a web socket connection will be retained.

The onOpen method – or rather the method annotated with @OnOpen – is invoked when a new client starts communications over the web socket channel. This method saves the session to the peers collection and returns a welcoming message to the new contact. Note how through the @PathParam annotated input parameter the method knows a little bit more about the client, provided the client did indeed add some content after the ‘regular’ Web Socket URL.

The method decorataed with @OnMessage is triggered when a message arrives on the Web Socket [channel]. In this case, the message is received and instantiated as a JSONObject. This would allow us to perform JSON style operations on the message (extract nested data elements, manipulate and add data). However, at the present, all we do is pass the message to each of the peers, regardless where the message came from (client-id) or what contents it contains. Note that the method would have to handle an exception if the message were not correct JSON data.

Finally the method with @OnClose handles clients closing their web socket channel connection. These clients are removed from the peers collection.

This particular WebSocket endpoint does not do anything that is special for the use case at hand. There are no references no movies, cinema events or whatever in this class. There could be logic that interprets messages, routes based on their content for example, but there does not need to be such business specific logic.

 

package nl.amis.cinema.view.push;

import java.io.IOException;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

@ServerEndpoint("/cinemaSocket/{client-id}")
public class CinemaEventSocketMediator {

private static Set peers = Collections.synchronizedSet(new HashSet());

@OnMessage
public String onMessage(String message, Session session, @PathParam("client-id") String clientId) {
try {
JSONObject jObj = new JSONObject(message);
System.out.println("received message from client " + clientId);
for (Session s : peers) {
try {
s.getBasicRemote().sendText(message);
System.out.println("send message to peer ");
} catch (IOException e) {
e.printStackTrace();
}

}
} catch (JSONException e) {
e.printStackTrace();
}
return "message was received by socket mediator and processed: " + message;
}

@OnOpen
public void onOpen(Session session, @PathParam("client-id") String clientId) {
System.out.println("mediator: opened websocket channel for client " + clientId);
peers.add(session);

try {
session.getBasicRemote().sendText("good to be in touch");
} catch (IOException e) {
}
}

@OnClose
public void onClose(Session session, @PathParam("client-id") String clientId) {
System.out.println("mediator: closed websocket channel for client " + clientId);
peers.remove(session);
}
}

Interact from REST service endpoint with WebSocket (endpoint)

The JSON messages received by the REST service exposed by class MovieEvent should be pushed through the Web Socket to the (external) clients, i.e. the web browser. There are two main options to hand these messages from class MovieEvent to the CinemaEventSocketMediator. One is through the use of CDI Events (as was mentioned above) and the other is by making class MovieEvent another client of the Web Socket [channel]exposed by CinemaEventSocketMediator. In this case, we opt for the latter strategy. Note that this means that there is no need for the MovieEvent class and the CinemaEventSocketMediator class to be in the same web application; their only interaction takes place across the web socket and they have no dependencies. I have them included in the same application for easy deployment. The same applies by the way to the client side of this article: the HTML and JavaScript that are loaded by the browser to present the dashboard to the end user. This too is currently included in the same web application and it too only has interaction over the web socket. There is no real reason for it to be part of the same application.

Using an excellent description on StackOverflow, I have created class MovieEventSocketClient with the @ClientEndpoint annotation. This class acts as a client to the Web Socket. It is the counterpart of the CinemaEventSocketMediator that is more or less the host or server for the web socket. The constructor for this class has two important steps: through the ContainerProvider (Provider class that allows the developer to get a reference to the implementation of the WebSocketContainer) a reference to the WebSocketContainer is retrieved (this is an implementation provided object that provides applications a view on the container running it. The WebSocketContainer container various configuration parameters that control default session and buffer properties of the endpoints it contains. It also allows the developer to deploy websocket client endpoints by initiating a web socket handshake from the provided endpoint to a supplied URI where the peer endpoint is presumed to reside. ) Using this container reference, through the connectToServer method, the client endpoint MovieEventSocketClient is connectedto its server. (This method blocks until the connection is established, or throws an error if either the connection could not be made or there was a problem with the supplied endpoint class.)

Class MovieEventSocketClient has methods annotated with @OnOpen, @OnClose and @OnMessage with more or less the same role as the counterparts in CinemaEventSocketMediator (and in the JavaScript client as we will see later). Note how in the @OnOpen annotated method the input parameter of type Session is retained and how in the method sendMessage this user session is used to send a message across the web socket.

package nl.amis.cinema.view.push;

import java.net.URI;

import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;

// based on http://stackoverflow.com/questions/26452903/javax-websocket-client-simple-example

@ClientEndpoint
public class MovieEventSocketClient {
public MovieEventSocketClient(URI endpointURI) {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(this, endpointURI);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

Session userSession = null;

@OnOpen
public void onOpen(Session userSession) {
System.out.println("client: opening websocket ");
this.userSession = userSession;
}

/**
* Callback hook for Connection close events.
*
* @param userSession the userSession which is getting closed.
* @param reason the reason for connection close
*/
@OnClose
public void onClose(Session userSession, CloseReason reason) {
System.out.println("client: closing websocket");
this.userSession = null;
}

/**
* Callback hook for Message Events. This method will be invoked when a client send a message.
*
* @param message The text message
*/
@OnMessage
public void onMessage(String message) {
System.out.println("client: received message "+message);
}

public void sendMessage(String message) {
this.userSession.getAsyncRemote().sendText(message);
}

}

Next we extend Class MovieEvent – the REST service that receives the JSON messages as HTTP POST requests – to interact with MovieEventSocketClient to pass the JSON messages to the Web Socket.

Method initializeWebSocket is added to instantiate MovieEventSocketClient with the address of the web socket. In postMovieEvent – the method annotated with @POST that handles the HTTP POST requests – a call is added to sendMessageOverSocket that hands the JSON message to MovieEventSocketClient  (after initializing it) to send it across the web socket (where it will be received in class CinemaEventSocketMediator).

 

package nl.amis.cinema.view;

import java.net.URI;
import java.net.URISyntaxException;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Request;

import nl.amis.cinema.view.push.MovieEventSocketClient;

//invoke at : http://localhost:7101/CinemaMonitor/resources/cinemaevent

@Path("cinemaevent")
public class MovieEvent {

private MovieEventSocketClient client;

private final String webSocketAddress = "ws://localhost:7101/CinemaMonitor/cinemaSocket";

public MovieEvent() {
}

private void initializeWebSocket() throws URISyntaxException {
//ws://localhost:7101/CinemaMonitor/cinemaSocket/
System.out.println("REST service: open websocket client at " + webSocketAddress);
client = new MovieEventSocketClient(new URI(webSocketAddress + "/0"));
}

private void sendMessageOverSocket(String message) {
if (client == null) {
try {
initializeWebSocket();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
client.sendMessage(message);

}

@POST
@Consumes("application/json")
@Produces("text/plain")
public String postMovieEvent(@Context Request request, String json) {
System.out.println("received event:" + json);
sendMessageOverSocket(json);
return "event received " + json;
}

@GET
@Produces("text/plain")
public String getMovieEvent(@Context Request request) {
return "nothing to report from getMovieEvent";
}
}

At this point, the application can be deployed. JSON messages sent to the REST service exposed by MovieEventSocketClient should be sent onward to the Web Socket (end point), leading to a message being written to the system output from onMessage in class CinemaEventSocketMediator.

Implement the HTML and JavaScript web application for the Cinema Monitor

The final piece in the puzzle discussed in this article is the client application to present the live status for the movie theater based on the web socket messages. It runs in a relatively modern browser – all standard browsers have HTML5 support which includes Web Socket interactions – and consists of an HTML page and two JavaScript libraries.

image

 

The HTML itself is relatively straightforward and boring.

image

Important are the <script> statements that import the JavaScript libraries that interact with the web socket and handle messages received over the web socket. The four rooms in the movie theater that are being monitored are represented by four TD elements with their id values set to room1..room4. These id values will be used in the JavaScript to locate the HTML element to update when a JSON message is received on the web socket for a particular room.

The imported JavaScript library websocket.js initializes the web socket connection to the end point ws://localhost:7101/CinemaMonitor/cinemaSocket. It configures JavaScript handlers for onOpen, onClose and onMessage. The latter is the most important one: any messages received on the web socket are checked for the string room. If the string is found, the message is handed off to the function updateRoomDetails(). This function is defined in the second JavaScript library moviemonitor.js.

var wsUri = "ws://" + document.location.host + "/CinemaMonitor/cinemaSocket/5";
var websocket = new WebSocket(wsUri);

websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
websocket.onopen = function(evt) { onOpen(evt) };

function onMessage(evt) {
console.log("received over websockets: " + evt.data);
console.log("looked for room index of: "+ evt.data.indexOf("room"));
var index = evt.data.indexOf("room");
writeToScreen(evt.data);
if (index&gt;1) {
console.log("found room index of: "+ evt.data.indexOf("room"));
updateRoomDetails( evt.data);
}
}

function onError(evt) {
writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
}

function onOpen() {
writeToScreen("Connected to " + wsUri);
}

// For testing purposes
var output = document.getElementById("output");

function writeToScreen(message) {
if (output==null)
{output = document.getElementById("output");}
//output.innerHTML += message + "
";
output.innerHTML = message + "
";
}

function sendText(json) {
console.log("sending text: " + json);
websocket.send(json);
}

The function updateRoomDetails in moviemonitor.js does not do a whole lot. It parses the input parameter from plain text with JSON format to a JavaScript memory structure. The function handleRoomUpdate is invoked with that JavaScript data structure – an object with properties room and occupation. The function handleRoomUpdate locates the TD element with its id set to room# where # corresponds wit the room property in the roomDetails input argument. It then sets the innerHTML of this element to the value of the occupation property. The result is an instant update of the room occupation value displayed in the user interface.

function updateRoomDetails( json) {
var roomDetails = JSON.parse(json);
handleRoomUpdate(roomDetails);
}

function handleRoomUpdate( roomDetails) {
var roomId = roomDetails.room;
var occupation = roomDetails.occupation;

var roomCell = document.getElementById("room"+roomId);
roomCell.innerHTML = occupation;

document.getElementById("message").innerHTML = roomDetails;
}

 

The screenshot shows the situation after a number of JSON messages have been received over the web sockets and the user interface has been updated accordingly.

 

image

 

Resources

Download the source code for the example discussed in this article: Zip File.

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

The Making of the World Cup Football 2014 Match Center ADF & AngularJS/HTML5 Application

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

This blog-post accompanies the OTN Article Marrying the Worlds of ADF and HTML 5 – to provide some details about setting up the environment for the ADF & HTML5/AngularJS World Cup Football 2014 Match Center application and about some implementation details in this application.

Development Environment

In order to inspect the applications, you will need to install JDeveloper 11g (11.1.1.7). This comes with its integrated WebLogic Server, and for running all but two of the ADF sample applications, that set up suffices. To also run the World Cup Football 2014 Match Center application itself, you will need to have access to an Oracle Database (XE or otherwise).

The easiest way to get hold of a complete environment – a VM with JDeveloper, the Oracle XE database and all sample applications up and almost running – is to follow the instructions in this article (that leverages Vagrant and Puppet to generate the VM for you and downloads the source code from GitHub): https://technology.amis.nl/2014/07/29/creating-automated-jdeveloper-12-1-3-oracle-xe-11gr2-environment-provisioning-using-vagrant-and-puppet/.

If you fancy a more manual set up procedure – which I can understand but would like to suggest against – you can find plenty of instructions for installing JDeveloper 11g (or 12c) and an Oracle Database. Additionally, you would have to clone the GitHub source repository that accompanies this article (https://github.com/pavadeli/adf-html5) or download the source as a zip-file (https://codeload.github.com/pavadeli/adf-html5/zip/master) and extract the zip-file to your local file system.

The file system would look like as shown in the next figure:

image

All ADF sample applications described in the article are in the sub folders adf, and adf-step1..6. Sub folder database contains the SQL scripts required for the creation of the database schema with the tables and types used by the World Cup 2014 application. Note: only the ADF applications in sub folders adf and adf-step1 actually need the database set up. All other sample applications run without database interaction.

We assume a database user schema (for example WC) has been created in the database and has been granted several system privileges, including connect, create session, create table, create or replace type and some quota on the default tablespace. Use SQL*Plus, SQLDeveloper or your favorite tool to create the database objects using the ddl.sql script. Then use the dml.sql script to load the data into the tables. The file queries.sql contains a number of sample queries against the database schema; these queries have been used in the ADF BC ViewObjects in the World Cup 2014 application.

After starting JDeveloper and opening either one of the two applications that require database access, look under application resources and set the properties for the database connection to the values appropriate for your environment. To test whether the settings are correct, you can run the ADF BC Application Module WorldCupService.

image

 

 

Special Features

This section is work in progress and will contain references to detailed explanation about certain features in the ADF World Cup Football 2014 Match Center application. By inspecting the code for the application you will find out the details on your own – it is all there. Below are some references to resources that were helpful in the creation of this sample application.

Some features that deserve special attention:

* Creation of the Language Selector and the Skin Switcher

* Using contextual events to communicate the current set of tags to the OTNBridge and eventually the tagcloud and to communicate the selected tags from the tagcloud via the OTNBridge to the host ADF Taskflow

* Refreshing the ADF BC ViewObject when a tag has been selected (and this has been published through a contextual event) (and ensuring that the contents of the table is refreshed as well)

* use of client side ADF JavaScript to communicate manual tag creation and deletion

* Opening the popup with taskflow inside from the context info element and passing the proper (match) context to the taskflow:

image

* Visualizing the match progress using panelGridLayout:

image

Resources

GitHub Repository with Vagrant (and Puppet) configuration files for the generation of the Virtual Box VM with the complete development environment including the sample applications: https://github.com/lucasjellema/adf-12-1-3-vm .

Some blog articles discussing the SQL queries behind the tag cloud and the group standings:

SQL Challenge: Find World Cup Football matches with a comeback

SQL Challenge: Drilling down into World Cup Football Tag Cloud

SQL Challenge: Dynamically producing a tag cloud for World Cup Football matches

SQL Challenge – World Cup Football 2014 – Retrieving matches and Calculating Group standings

Use REGEXP_SUBSTR for string tokenizing https://blogs.oracle.com/aramamoo/entry/how_to_split_comma_separated_string_and_pass_to_in_clause_of_select_statement

Add logging: http://blog.iadvise.eu/2013/01/02/starting-with-adf-11g-logging/ in ADF applications

Note: popup and setpropertylistener do not go together well (https://community.oracle.com/thread/677678?start=0&tstart=0, https://community.oracle.com/thread/2235404?start=0&tstart=0, http://amit-adf-work.blogspot.nl/2012/12/adf-issue-with-popup-and.html )

http://www.jobinesh.com/2010/10/how-to-set-bind-variable-values-at.html

http://dailydevfixes.blogspot.nl/2011/07/setting-bind-parameters-on-hierarchy-of.html

http://jdeveloper-adf.googlecode.com/svn/trunk/TGPrototype2/ViewController/src/com/tgslc/defaultManagement/utils/ADFUtils.java

Set width for panelCollection: http://cbhavsar.blogspot.nl/2008/10/using-panelcollection-with-master.html

Help on PanelGridLayout: https://formattc.wordpress.com/tag/panelgridlayout/

Stretching in various ADF Faces components: http://www.adftips.com/2010/11/adf-ui-tips-to-stretch-different-adf.html

Introducing ADF Faces Contextual Events:  https://technology.amis.nl/2013/03/14/adf-re-introducing-contextual-events-in-several-simple-steps/

Add componentUI reference in TagCloudBean; www.jobinesh.com/2011/06/safely-storing-uicomponent-component.html

Add resource bundle and language switcher https://technology.amis.nl/2012/08/11/supporting-multiple-languages-in-adf-applications-backed-by-resource-bundles-and-programmatically-controlling-the-jsf-locale/ and

https://technology.amis.nl/2012/08/09/introduction-to-resource-bundles-in-adf-applications-for-centralizing-management-of-boilerplate-text/

Introduction to skinning: https://technology.amis.nl/2009/07/01/using-adf-faces-11g-skinning-for-setting-the-styles-of-specific-component-instances-or-groups-of-instances/ and

http://docs.oracle.com/cd/E28280_01/web.1111/b31973/af_skin.htm and Skin (Switcher): http://docs.oracle.com/cd/E18941_01/tutorials/jdtut_11r2_83/jdtut_11r2_83.html

Presentation on slideshare with some visualizations of the mechanisms in the World Cup Football 2014 Match Center application: http://www.slideshare.net/lucasjellema/marrying-html5-and-angular-to-adf-oracle-openworld-2014-preview.

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

Developing the AngularJS Tagcloud application – appendix for Marrying the Worlds of ADF and HTML5

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

This blog-post accompanies the OTN Article Marrying the Worlds of ADF and HTML 5 – to provide some details about setting up the HTML5/AngularJS development environment and about the development of the AngularJS application.

Get hold of the sources

All sources associated with the article are available from GitHub: https://github.com/pavadeli/adf-html5. You can clone this GitHub repository or download the sources in a zip-file that you can subsequently extract locally. The directory structure that you will end up with looks like this:

image

 

The top folders contain the ADF application with embedded AngularJS component, the lower (html-…) directories contain the pure HTML5 & AngularJS applications.

Set up the Development Environment

Just like JDeveloper is the IDE for ADF application development – including facilities for library management, building and deploying the application and with the integrated WebLogic Server as the run time engine, we need an environment to develop the rich client, HTML5 & AngularJS application. We use a different set of tools in this environment – and while you have some choice, we suggest the following combination of tools:

–IDE: Sublime Text Editor

–Package Manager: Node.js – NPM

–Build (Ant-like): Gulp

–Dependency Management (Maven-style): Bower

–Run Time: Google Chrome browser

Install node.js (http://nodejs.org/). This will give you access to the Node.js Package Manager (NPM). With NPM you can install Gulp (build tool, super hip, does for JS what ANT does for Java) and bower (dependency management, is to JS what Maven is for Java)

Open the command line and type:

> npm install -g gulp bower

This will install both gulp and bower on your local file system.

To build the pure HTML5 sample applications in the folders html-step1, html2-step2 and html, you have change the current directory to each of these folders respectively and for each perform these steps:

> npm install

to fetch all design-time dependencies (the tools used via gulp). The file package.json tells NPM what to install:

image

Next, to fetch the run time dependencies (which means: AngularJS):

> bower install

This instructions results in the creation of the bower_components subdirectory with various JavaScript components downloaded from GitHub or some other git endpoint. The packages that Bower should install are configured in the file bower.json:

image

After running bower install you can run bower list to see the list of installed packages:

image

Note that the angular component as well as the bower-tagcanvas are known to bower (as you can check in the bower directory of components at http://bower.io/search/). Details about a [bower]package can be retrieved with bower info [package name]:

image

The next command starts the build server (Gulp):

> gulp serve

This will not take long (maybe two seconds), and will open a browser window. In the command line window, you will see an indication of the host and port at which you can access the server:

image

The actions performed by Gulp are defined in the gulpfile.js file. This file defines for example that gulp serve will publish all files in the current directory (./) and will watch for changes to all files with extension .html and inside the components directory:

image

Run the sample applications

When you started the build server with gulp serve, the run time server was started – this server provides resources to the associated run time presentation engine: the browser. Real AngularJS developers seem to only use Google Chrome, so open that browser, and point it at the URL suggested in the command line window by the Gulp Server – with /tagcloud-html.html appended (for the folder html-step1):

image

You can open the main source file for this application, in for example Sublime Text editor:

image

Add a new value for a link and save the text file. You will notice that without refreshing, the browser updates the page (thanks to a Web Socket channel to the Gulp Server):

image

Stop Gulp and change to the html-step2 directory

image

Open the tagcloud-bridge.html document in the browser window:

image

This application contains the bridge module into which the guest-tag-cloud component has been injected. Both tagclouds shown in the page are completely independent instances of the same AngularJS module.

Note: instead of checking out the html-step1 and html-step2 directories, you could also immediately go to the html directory, start the Gulp server and open the index.html document that gives access to both page:

image

The AngularJS modules – bridge and tagcloud – can be packaged into a couple of JS files that can easily be integrated into other applications, such as an ADF application. You achieve this through the command “gulp”. This will trigger the default action in the gulp.js file, which states that both integration and tagcloud should be built:

image

The result of this action should be written to directory ../adf/ViewController/public_html/scripts, which is part of the ADF application that embeds the tagcloud component.

image

Note that a typical gulp build pipeline may also contains steps for

  • Minification (reducing the size of the JS file, often with up to 70 – 80%)
  • Jslint (static code checking, similar to Sonar in Java )
  • Various preprocessing / checking tasks

Exploring the AngularJS application

Without diving too deeply into AngularJS there are some things to point out in the AngularJS applications.

A good place to start is in the file tagcloud-html.html:

image

At (1) we see a custom HTML tag, tag-cloud. We can use this tag because HTML5 allows custom tags, we engage AngularJS and in the tagcloud.js file – that is imported and defines the included tagcloud module – we have defined an AngularJS directive that instructs Angular to relate this tag to the tagcloud module.

At (2) we see an Angular data binding expression: {{log}} will result in the contents of the log variable in the Angular scope to be returned. At (7) (see below), we see how we put a function on the scope as tagClicked. This function will be invoked whenever a tag is clicked in the tagcloud. The function will create a string and put that in the scope as log. Because of Angular’s two-way databinding, the update of log in the scope by this function will immediately result in an update of the contents of the <pre> tag in the page.

At (3) we see the import of the JavaScript libraries – two were created by bower and one is our hand-crafted Angular module tagcloud, to be discussed below.  At (4) the Angular App myApp is initialized with dependencies on the tagcloud module. A controller is set up for myApp and defined with an anonymous function. This function puts a collection called tags on the scope with values that represent a simulated initialization phase. After a timeout of 2 seconds (2000 ms), a new value for tags is put on the scope (6). Again, through two way data binding (and the watch function defined for tags in the tagcloud.js file), the consumer of the tags variable will be updated on both occasions when the tags variable is set.

image

 

Let’s take a look at tagcloud.js – the file that defines the Angular tagcloud module. At (1) we see the definition of the module tagcloud, which does not have dependencies on any additional modules. At (2) is the derivation of the unique id for each instance – every occurrence of the tag-cloud custom HTML tag. At (3) the directive specifies that an HTML element of tag-cloud (which is the automatic conversion of camel case tagCloud) is to be associated with this module. At (4), the private (data) scope for this module is defined, containing the elements tags and tagClicked. This is crucial in order to be able to have multiple instances of the tagcloud in a single page that are isolated from each other. Each instance has its own tags and its own tagClicked function.

At (5) we indicate the external HTML file that provides the ‘view’ content for our tagcloud module. The tagcloud.html file is shown below.

Directives that want to modify the DOM typically use the link option, shown at (6). One very important element set up in this link() function is the watch function that we associate with the tags collection (on the scope). Whenever the value of tags changes, this function will be executed. In most situations, the result will be that the Start function on the TagCanvas object is invoked – to redraw the tagcloud [with the latest set of tag values].

image

The HTML file that is imported at (5) is actually very simple:

image

A new canvas is rendered with an id value based on the canvasId value in the Angular scope – where we have taken care to make this value unique. The ng-repeat attribute is interpreted by Angular, creating a for each loop that stamps out the <li> element for every element in the tags collection (on the scope). For each tag, an <a> element is rendered with attributes data-weight and click derived from properties of the tag element in the tags collection and the tagClicked() function that was put on the scope at (7) in tagcloud-html.html.

A visualization of the application structure is shown next:

image

Resources

What’s so great about Angular by Ben Lesh – http://www.benlesh.com/2014/04/embular-part-2-whats-great-about-angular.html

Getting Started With Gulp by Travis Maynardhttp://travismaynard.com/writing/getting-started-with-gulp

Gulp as a Development Web Server by Johannes Schicklinghttp://code.tutsplus.com/tutorials/gulp-as-a-development-web-server–cms-20903

Getting Started with Bower – blog article with introduction tutorial to Bower for managing JavaScript dependencies

AngularJS – documentation on the Directive, watches

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

Live Blog – AMIS Oracle Enterprise Mobility conference (21-23 May 2014) – Last Updated May 23rd – 16:30 CET

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

SNAGHTML5d1bac.png

This article will provide a live account of the three day Enterprise Mobility conference, hosted by AMIS in Nieuwegein, The Netherlands. Oracle ADF Product Managers Frank Nimphius and Chris Muir are the keynote speakers. They are joined by Willem de Pater, Steven Davelaar and Lancy Silveira from Oracle and Luc Bors, Frank Houweling, Paul Swiggers, Aino Andriessen and Lucas Jellema from AMIS. The presentations and demonstration during this conference cover the next step for most enterprises (with ADF or without): introducing enterprise mobility. Many of the themes currently or shortly relevant to any organization will take center stage: multi device UI, mobility, security, agile & automated software engineering, performance & scalability, user experience, web & mobile oriented architecture and cloud. It will discuss and demonstrate Oracle’s vision and the upcoming generation of products.

The audience is composed of about 40 experienced ADF application architects and developers that not just sit back and relax, but share their experiences and ask the tough questions. How well does ADF fit in the mobile world? What is the role of ADF in a future that consists of HTML 5 and mobile? What is the long term evolution of ADF – and the use Oracle itself makes of the framework?

Note: the Twitter hash tag for this event is #amis_m2e (follow us on Twitter: live twitter-feed)

Friday 23rd May

16:30 Aino is still going strong. He is advocating the use of automation in our build, test and deployment processes. To use Maven (with 12c) and Ant (for 11g). To use Hudson or Jenkins to organize frequent, automated build in our development and testing environments and to perhaps look a little bit further (XL Deploy, Bamboo, Go) when it comes to deployment strategies for Acceptance Testing and Production environments.

imageimage

Aino badgers us about software craftmanship. Code quality, leaving code better than we found it, being proud of code. Ensure that our code is clear, readable, well documented to explain implementation decisions. I quite agree with him. Using terms like stuff, junk or even crap (meuk, zooi, bagger) to refer to your own (team’s) software when talking about compiling, checking in or building is common and is very wrong! Very unprofessional.

image15:09 Aino started the last session of the conference: Continuous Delivery and ADF – Manage the modular architecture. He comments how fitting it is that application architecture, testing and continuous deployment are discussed at the end of the conference – as they are typically dealt with in fairly late stages in most projects too. Even though they are hugely important.

Aino discusses possible modular architectures for ADF applications – ways to organize the ADF application in a way that makes the development work and the deployment, versioning, resue and testing manageable.image

13:47 Frank starts his presentation on the Oracle Application Testing Suite. First of all: what is the cost of not properly testing an application – functionally and performance oriented – before introducing the application into production.

 

 

12:25 A lot of questions and some discussions during Frank’s presentation. He talks about many things, including the ADF BC configuration parameters, the memory scope of managed beans, the JVM Heap Space settings, the rangeSize of ViewObjects, the use of specialized VOs for Form and Table pages.

image

He then demonstrates the HR Application from Hell – and shows how to analyze the extremely poor behavior of this application.

More information – and some webcasts – on the ADF Performance Monitor and how to fix the application from hell can be found on: http://www.amis.nl/ADFPerformanceMonitor.

image

11:58 Frank Houweling is about to start his presentation on performance monitoring, analysis and tuning – all the way down, from ADF Faces via ADF BC into the JVM gaining insight into the internals and acting on that insight. Chris Muir does a very good job of introducing Frank, highlighting the AMIS ADF Performance Monitor that Frank has worked on for the last three years. This tool is very good at providing fine grained as well as aggregate insights in the performance of ADF applications and identifying the exact pain points in the ADF application. The tool analyzes all steps in both the ADF Faces, the ADF Binding and the ADF BC tiers of the application, allowing quick pin pointing of the potential improvement points in the ADF application. Many best practices and common mistakes are recognized by this tool.

11:00 Paul Swiggers introduces Real User Experience Inside (RUEI), specifically applied to ADF applications.

image

10:20 Frank Nimphius presents ADF Programming – Best Practices
(his slides were very similar to http://www.slideshare.net/Berryclemens/con3075-nimphius-con3075programmingbestpracticesbeginneradffusionapps)

09:45 Chris Muir is done presenting the wonderful By the Poolside presentation in which he manages to turn this tough topic into a very clear, enjoyable and educational session. He divulges the following URL as an exclusive sneak preview to the video recordings of this presentation (nothing like the live experience of course, but still very valuable.

image

07:12 The final day of this three day event. I am sure it will add even more value to what already has been a very valuable event. After last night’s ADF Community Event and the kick off of the AMIS & Oracle ADF FIFA World Cup Football challenge and the launch of the XML Data Control ADF EMG open source project by Wilfred and Richard (see http://t.co/gF64zuP9SZ) , some fatigue may set for the speakers (especially Chris and Frank who are doing outstanding jobs).

 

Thursday 22nd Mayimage

21:03 A Hot May Night – time to hit the bar (and continue the discussions there). Frank and Chris have just concluded their presentation for the ADF Community Night. They have enthused the audience with the next steps to come with ADF (12.1.3, 11.1.1.9, 12.1.4 and beyond). They have been slightly grilled by the audience and probably a little bit more by the heat generated by the warm May night and the over 60 ADF developers attending the session.

 

19:00 After the dinner buffet (out on the terrace on account of the pretty good weather conditions), there is a special announcement by Wilfred van der Deijl and Richard Olrichs.

image

This pair of top ADF specialists have collaborated – as part of a project at Dutch financial institute MN – on what is duped the XML Data Control. They publish this component as an ADF EMG open source project (courtesy of MN). Their use of the Safe Harbor slide is a tongue in cheek reference to Frank’s and Chris’s reliance on that slide to waive any responsibility for whatever they present afterwards.

image

The XML Data Control is an ADF Data Control that is used by developers to create data bindings in ADF Faces pages, just like the ADF BC Data Control and the POJO Data Control. The data exposed through this data control can be any XML source – from a SOAP or REST WebService, from a static XML document or a custom Java Class that produces an XML document from anywhere. It offers much more control and flexibility than the Web Service Data Control does (that is very limited in scope and usability).

imageimage

Through this XML Data Control, it will become very simple for developers to leverage fairly complex web services or any other XML producing provider in ADF applications. Additionally the source for this component will be a great example for developers to see how custom data control can be developed.

In the very near future, an official launch event for this component will be held on the premises of MN in The Hague. To attend this event or to be informed about the next steps with the XML Data Control, you can register at: . The slides for Wilfred’s and Richard’s presentation are here: .

17:59 Last minute preparations by Wilfred and Richard:

SNAGHTMLef7db4f

17:45 The ADF Community Night starts. Brian Wolff (Oracle) and Luc Bors (AMIS) & announce the AMIS & Oracle ADF World Cup Football 2014 Challenge – develop an ADF app(lication) associated with the World Cup Football 2014 and win the Oculus Rift 2 VR glasses.

Will this team (Paco and Wilfred) compete too?

image17:25 Chris is close to concluding the first part of his presentation on ADF BC Application Module Pooling. This is undoubtedly by far the best (and most fun) explanation of what are extremely important and intrinsically complex subjects. Incredible how well the audience engagement still is at this time of the (long, hot and intensive) day!

Chris indicated that his presentation (in the form of a series of video recordings) will soon be available on OTN. As you probably understand gather: it is highly recommended.

image

SNAGHTMLe081425

15:30 Lancy and his “groupies” after his presentation. They want to hear more (and more and more)

image

Download the eBook on realizing UX and Simplified UI using ADF: tinyurl.com/SimplifiedUI.

15:00 Lancy in the middle of his very entertaining session on implementing UX using ADF Faces. “We use the new Deck component like hell”.

imageimage

The Deck component (ADF 12.1.3) is rendered as a card that can be flipped. The card can have two faces, or many more. The flip-method can be configured, using various animations (similar to slide transitions).

image

Some examples of creating nice UI implementations using ADF Faces – using components such as Spring Board, Panel Drawer, PanelTabbed:

image

image

image

Glance, Scan Commit

Lucas introduced the notion of Glance, Scan, Commit in general terms:

image
Lancy takes that concept and explains it in UX terms:

image

14:00 – Lucas Jellema presents on User Experience (really the lead-in to Lancy’s presentation). See for the slides:

 

12:55 After the lunch break, Steven Davelaar is presenting a very challenging demo – using ADF Mobile against a REST interface put on top of the BPM Suite and the Human Workflow service. He demonstrates a Claims processing app (and backend) where an insurance claim can be submitted from the mobile device – including pictures taken at the seen and documents associated with the claim – causing a BPM process to be triggered.

image

Claims handling staff can use their own Oracle mobile app to get an overview of the tasks waiting for them – rather the claims they have to review. Each task can be handled very easily (glance & scan) from the mobile device. Dealing with a claim will then cause the BPM process to continue. To top if of, Steven showed how the ‘local persistency mechanism’ in Oracle’s Mobile solution allows the app to present the claims even when in off-line mode.

Negotiating an intricate path between all the devices he brought to the party and the many steps in the demo, Steven did a very good job of demonstrating the integration between many of the bits and pieces we have discussed over the last day and a half.

11:00 Lucas Jellema – The mobilization of SOA Suite – the rise of REST

See for the slides for this presentation: .

10:21 Frank Nimphius – The REST-side story.

Even though some of Frank’s demos are challenging, he seems pretty relaxed:

image

Embedded image permalink

10:13 Remotely Wiping a Container

After wipe, container App is still on the device, but the configuration is lost (as is the data associated with the container).

image

When the container is started again, the user can access the ‘container catalog’ and have the container reinitialized based on the selected configuration. This includes reinstalling the apps that were previously part of the wiped container.

image

image

Note: The container can be used in off line mode too.

Note: there is no ‘restore container after wipe including all documents and app data'( there is no container-back-up mechanism)

To initially get going with the enterprise secure mobile container, we can simply have an LDAP user sent an email with a URL that the user can click to start the installation procedure:

image

10:03

Enterprise Admin console

logging in: image

 

dashboard of container management:

image

details of a specific container:

image

Catalog of containerized apps

 

Add new app of type Web (site)

image

image

And see it in the catalog

image

 

 

image

Also: add SMB server path

image

Also: upload/register containerized app.

Users are managed using existing IDM solutions – such as Active Directory or OID. These details are available in the Mobile Security Container Admin Console.

09:47 The containerization of an app: no SDK required, the App is not modified. Can be done for custom built apps as well as COTS apps. The process of containerization adds a security layer around the app. In the process the unsigned app gets the APK injected and is signed with a corporate certificate. It is a straightforward, simple process that takes minutes or less.

After these steps, the ‘container-enabled’ app is added to the catalog, from which it can be added to mobile container instances. Container == Enterprise Mobile Workspace (shared by all containerized apps).

Microsoft is not yet willing to make unsigned versions of its apps available. Note that an app has to be unsigned in order to be containerized.

image

09:27 To put apps in the secure mobile container is fairly straightforward: it is a simple process of selecting apps from the corporate catalog and signing the app with your own certificate.

image

Right now the option to take a screenshot – while the secure container is shown on the screen- cannot be disabled. However, if the screen is showing anything that should be kept secret, taking a picture of the screen with an external camera has the same effect.

Note: this white paper provides more information: http://www.oracle.com/us/products/middleware/identity-management/mobile-security/secure-adoption-of-byod-wp-2199321.pdf .

The App Tunnel – the secure connection between the mobile app container and the enterprise back end – does not require a VPN connection.

09:09 – After a brief recap of day one and an overview of what day two is going to bring, Willem de Pater (Oracle) starts his presentation on Oracle’s Mobile Security strategy – focusing on the Bitzer acquisition (Bitzer in bits). Note how very up to date these details on mobile device theft really are (see lower left hand corner):

image

A crucial aspect of the Bitzer offering is the ‘application container': a secure container in which corporate applications and data can be installed and managed. It is this container that should be secured by the enterprise and that should be remotely wipeable by the enterprise when the device is lost or the employee is. The container has a number of standard apps out of the box – such as a web browser, a file manager, secure email, document editing etc.

The network rules that apply to the corporate network can also made to apply to the secure mobile container: if you cannot access Dropbox from your desktop in the office, neither can you access Dropbox from within the container on your BYOD device. However, outside the container on that device, you can still access Dropbox.

08:58 – Everyone eagerly seated and awaiting day two of the Enterprise Mobility conference. Well, perhaps it took us until 9:02 to get everyone in the room, but no longer.

Wednesday 21st May

image17:01 – Chris shows a video with a number of examples of apps developed with Oracle’s Mobile development technologies. This video is available at http://www.oracle.com/us/corporate/events/oracle-cloud-forum/index.html PaaS & IaaS – Part 2

image

16:54 – Chris is back on to discuss the various mobile solution areas Oracle is offering. Currently he talks about security. Things like: how to guarantee that our enterprise apps do not store passwords in clear text? How do we make sure that all (relevant) network communication to and from mobile apps is secure (transport layer, encryption)? How do we manage the BYOD devices – ensuring that the enterprise cannot access, read or wipe the personal data on the BYOD yet how do we ensure that when the device is lost or stolen or when the employee leaves the organization all the enterprise stuff on the device can be removed? The Bitzer acquisition offers functionality to take of these requirements.

15:47 – Steven is in the middle of a complex demo of how REST data services can be used to provide data to the ADF Mobile application (and how these are ideally accessed using a business objects layer that allows the app to also run against a local storage (a very crude summary of what he is doing).

imageSee the A-Team blog articles on Implementing Data Caching and Data Syncing for more details.
Steven’s slides (although the demo is of course what really brings it to life):

15:10 – Popsicles for our tea break; well deserved and needed because of the hot day and the exciting presentations…

imageDuring this break, some presenters are discussing and preparing for the next sessions (Steven, Chris and Lance)

image

 

14:55 Chris: You do not need ADF at all (in the back end) to be using ADF Mobile! It is the same programming paradigm. It is not the same technology!

14:33 Luc completed a very thorough overview of ADF Mobile. He demonstrated how to implement a number of fairly advanced application features (including a custom spring board and push notification (!). Luc’s book will go production in Q3 2014 (around OOW that should be)

13:45 “As soon as anything goes into production, it is legacy” says Chris Muir. Chris discusses a number of enterprise mobile challenges, including the lack of resources to develop iOS/Android applications for the enterprise environment.

image

13:17 We have resumed – after a nice outdoor lunch in great weather with lively discussions (as much about World Cup Football as about ADF), we have reconvened for an afternoon of ADF Mobile – with Chris, Steven and Luc.

imageSNAGHTML403acc7

12:45 – Lunch:

image

12:17 – Device integration from ADF Faces is not so hard in certain situations: add prefix in destination attribute of goLink component (mailto: , tel:).

Steven manages to engage the audience, even when their minds start to turn to lunch:

image

12:05 – Steven explains how device specific UI component manipulation can be implemented in a generic way in ADF Faces using a JSF Phase Listener that triggers a VisitCallback implementation in the before RenderResponse phase. Examples are: adapt table scrolling to device with proper fetchSize and autoHeightRows and pagination controls (note: 12.1.3 introduces tablet-optimized-scrolling), conditionally switch off features that do not make sense on the current device, add inline overflow on small screen device to cater for wide tables.

11:49 – in ADF 12.1.2 – clientListener of type mediaEvent . Traverse client side component tree in generic, complex JavaScript code. In 12.1.4: declarative component tag for adding media behavior. Cool website to check browser support on features

Embedded image permalink11:29 – Steven is getting off to a very good start with setting himself a serious challenge – showing code, demonstrating applications and staying on time.

Steven discusses how ADF Faces applications can be adjusted for tablets – still browser based, still also used on desktop browsers. Provide a good user experiences, use the form factor and screen size as appropriate on each device and also handle touch based gestures.

See Stevens slides here:

 

 

11:10 – Frank is in the middle of this key note on mobile (Mobile is eating the enterprise) in which he explains how pervasive mobile has become, for the world in general and for the enterprise environment in specific. Some keywords: Mobile first, adaptive design and responsive layout.

Embedded image permalink

 

09:53 ADF 12.1.4 brings the notion of Remote Regions. Embedded image permalinkThis would allow an ADF application to have regions based on task flows deployed in other applications (that run either on the same WebLogic Server instance or a different, remote one). Similar to WSRP Portlets – but geared towards ADF (and hopefully usable). It should cater for contextual events being exchanged between the remote region and the local application (however, obviously, no transactions or session state can be shared).

 

9:47 Frank mentions the Alta look and feel that is expected in the ADF 12.1.4 timeframe – to be used with both Mobile and Web applications (with a somewhat iOS7 like look and feel):

Embedded image permalink

09:12 Frank and Chris get the show on the road with their ‘State of the ADF nation’ presentation about past, present and future of ADF.

They ask the audience whether anyone is still on ADF 9.0.5 (no one is) and who is on 10g, 11gR1 or 11gR2. ADF 12c seems to have relatively small uptake; perhaps we are all waiting for 12.1.3 – soon to be released (no date given).

12.1.2 new feature: af:target component (to do more fine grained partial page refresh).

ADF 12.1.3 will be part of the full breadth FMW 12.1.3 release. It provides a lot of features – no large architectural changes.

DVT has been extended and improved (including nice thematic map features and the diagrammer chart component as well as new gauges and an interesting looking dependencies visualization component.

 

09.00 (well, 9:03 perhaps) – Kick off of the Enterprise Mobility conference – introducing the speakers, the objectives and the roadmap for the three days. This includes the ADF Community Night on Thursday (22nd  May). This might be an event to celebrate the 10 year anniversary of ADF (which I believe was first launched in 2004). AMIS celebrates about 14 years of working with ADF and its immediate predecessors (BC4J).

Embedded image permalink

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

ADF for the Enterprise and beyond – 3-day conference for senior developers and application architects

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page

SNAGHTML5d1bacOn May 21st, 22nd and 23rd – AMIS and Oracle join forces for a three day event around enterprise application development with Oracle Fusion Middleware. The event targets senior (ADF) developers and application architects. It addresses many of the themes currently or shortly relevant to any organization: multi device UI, mobility, security, agile & automated software engineering, performance & scalability, user experience, web & mobile oriented architecture and cloud. It will discuss and demonstrate Oracle’s vision and the upcoming generation of products.

This event takes place in The Netherlands (Nieuwegein, 35 minutes from Schiphol Airport). If you are in the Western European region and active in the area of Fusion Middleware, we suggest you seriously consider attending – as this is a fairly rare opportunity to hear from and interact with Oracle product managers (up close and personal) and several seasoned speakers as well as an audience composed of your peers, sharing their experiences and insights. The event is small scale and set up for easy interaction between all participants. Registration can be done here – the conference fee for the full three days (including lunches, drinks and snacks) is set at 750 euros.

Enterprise to mobility event AMISSpeakers at the conference are Chris Muir and Frank Nimphius (both from Oracle ADF Product Management)

joined by: Willem de Pater (Security Solution Architect Oracle), Steven Davelaar (Oracle A-Team) and Lancy Silveira (Oracle UX team), Wilfred van der Deijl (AMIS Associate and Oracle ACE Director), Luc Bors (AMIS, Oracle ACE), Lucas Jellema (AMIS, Oracle ACE Director), Frank Houweling (AMIS), Paul Swiggers (AMIS), Aino Andriessen (AMIS).

Continue reading

Share this on .. Tweet about this on TwitterShare on LinkedInShare on FacebookShare on Google+Email this to someoneShare on TumblrBuffer this page