<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog4Java</title>
	<atom:link href="http://malsolo.com/blog4java/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://malsolo.com/blog4java</link>
	<description>A personal and Java blog, likely only for me</description>
	<lastBuildDate>Tue, 31 Mar 2015 15:52:42 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=4.1.1</generator>
	<item>
		<title>Getting started with Docker</title>
		<link>http://malsolo.com/blog4java/?p=794</link>
		<comments>http://malsolo.com/blog4java/?p=794#comments</comments>
		<pubDate>Tue, 31 Mar 2015 15:51:23 +0000</pubDate>
		<dc:creator><![CDATA[Javier (@jbbarquero)]]></dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Docker]]></category>

		<guid isPermaLink="false">http://malsolo.com/blog4java/?p=794</guid>
		<description><![CDATA[What is Docker? Docker is a platform. Docker runs natively on Linux or on OS X and Windows through a helper application called boot2docker that creates a Linux Virtual Machine, by using only RAM, to run Docker. Docker&#8216;s main goal &#8230; <a href="http://malsolo.com/blog4java/?p=794">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<h1>What is Docker?</h1>
<p><a href="https://www.docker.com/whatisdocker/" title="What is Docker?" target="_blank">Docker</a> is a platform.</p>
<p><a href="https://docs.docker.com/introduction/understanding-docker/" title="Understanding Docker" target="_blank">Docker</a> runs natively on Linux or on OS X and Windows through a helper application called <a href="https://github.com/boot2docker/boot2docker" title="boot2docker at GitHub" target="_blank">boot2docker</a> that creates a Linux Virtual Machine, by using only RAM, to run Docker.</p>
<p><a href="https://docs.docker.com/" title="About Docker" target="_blank">Docker</a>&#8216;s main goal is to allow you to ship distributed applications, that you&#8217;ve created previously, by running them as isolated process on what is known as a <em>container</em>, thus it avoids the need of Virtual Machines that implies a resources saving in the involved machines. The isolation also allows to run several containers simultaneously.</p>
<p>So, <em><strong>Docker</strong> is an open platform for developing, shipping, and running applications</em>.</p>
<p>The key point is that you can separate your application from the infrastructure and also treats the infrastructure as an application. Everything can be packaged, distributed and deployed anywhere and quickly. It&#8217;s said that Docker eliminates the friction between development, QA, and production environments.</p>
<p>Docker has two major <strong>components</strong>:</p>
<ul>
<li><a href="https://github.com/docker/docker" title="Docker at GitHub" target="_blank">Docker</a>, the container virtualization platform, that has a <em>daemon</em> running on a host server and a client (the <em>docker</em> binary) to talk to the Docker <em>daemon</em>.</li>
<li><a href="https://hub.docker.com/" title="Docker Hub" target="_blank">Docker Hub</a>, the <a href="http://en.wikipedia.org/wiki/Software_as_a_service" title="Software as a service at Wikipedia" target="_blank">SaaS</a> platform for sharing and managing Docker containers.</li>
</ul>
<h2>Docker concepts</h2>
<ul>
<li><strong>Image</strong> (<em>build</em> component of Docker): a Docker environment template, it consists in files (a copy of what is expected to contain) and metadata (information such as environment variables, port mappings and so on) and it has a name (<em>&#8220;ubuntu&#8221;</em>, for instance)</li>
<li><strong>Registry</strong> (<em>distribution</em> component of Docker): a public or private store that holds images. The public Docker registry is called <a href="http://hub.docker.com/" title="Docker Hub" target="_blank">Docker Hub</a>.</li>
<li><strong>Container</strong> (<em>run</em> component of Docker):  a running instance of a Docker image. It&#8217;s created from a Docker image, and it can be run, started, stopped, moved, and deleted. Each container is an isolated and secure application platform.</li>
</ul>
<h2>How Does Docker work?</h2>
<p>An image is a serie of layers that are combined into a single image by Docker using <em><strong>union file systems</strong></em> (<a href="http://en.wikipedia.org/wiki/UnionFS" title="UnionFS at Wikipedia" target="_blank">UnionFS</a>, <em>a file system service that allows files and directories of separate file systems, known as branches, to be transparently overlaid, forming a single coherent file system</em>)</p>
<p>From a base image, you can add and modify additional layers and there&#8217;s no need of rebuilding the entire image if there is a change, you only need replace the added or updated layer.  </p>
<p>A container is built from an image, that is read-only. For running the container, Docker adds a read-write layer on top of the image (using UnionFS) and then allocates a network/bridge interface, an IP address, and finally, executes the specified process and captures input and provides output.</p>
<p>The container is isolated thanks to a technology called <em><strong>namespaces</strong></em> (<a href="http://en.wikipedia.org/wiki/Cgroups#NAMESPACE-ISOLATION" title="Namespaces at Wikipedia" target="_blank">Namespace isolation</a>, <em>where groups of processes are separated such that they cannot &#8220;see&#8221; resources in other groups</em>)</p>
<p>Docker use these namespaces:</p>
<ul>
<li>The <strong>pid</strong> namespace, for process isolation.</li>
<li>The <strong>net</strong> namespace, for managing network interfaces.</li>
<li>The <strong>ipc</strong> namespace, for Inter-Process Communication.</li>
<li>The <strong>mnt</strong> namespace, for managing mount-points.</li>
<li>The <strong>uts</strong> namespace, for changing the hostname.</li>
</ul>
<p>In order to achieve isolation on running application, Docker uses another technology called <em><strong>control groups</strong></em> (<a href="http://en.wikipedia.org/wiki/Cgroups" title="cgroups at Wikipedia" target="_blank">cgroups</a>, <em>it limits, accounts for, and isolates the resource usage (CPU, memory, disk I/O, network, etc.) of a collection of processes</em>)</p>
<h1>Installing Docker</h1>
<p>I&#8217;m going to use <a href="http://www.ubuntu.com/" title="Ubuntu: The leading OS for PC, tablet, phone and cloud" target="_blank">Ubuntu</a> (as <a href="http://en.wikipedia.org/wiki/Sheldon_Cooper" title="Sheldon Cooper at Wikipedia" target="_blank">Sheldon Cooper</a> said, <a href="http://www.imdb.com/title/tt1648756/quotes?item=qt1224150" title="Sheldon Cooper and Ubuntu" target="_blank">my favorite Linux-based operating system</a>)</p>
<p>There are <u>three packages available</u>, two of them from Ubuntu, an older KDE3/GNOME2 called <em>docker</em> (warning, this is the suggested package when you try <em>docker version</em> before having installed: <em>&#8220;The program &#8216;docker&#8217; is currently not installed. You can install it by typing: sudo apt-get install docker&#8221;</em>) and a newer called <em>docker.io</em>, that is not the most recent Docker release. The third one is a PPA (Personal Package Archives for Ubuntu) for <a href="http://www.ubuntuupdates.org/ppa/docker" title="3rd Party Repository: Docker" target="_blank">Docker</a> and it&#8217;s called <a href="http://www.ubuntuupdates.org/package/docker/docker/main/base/lxc-docker" title="Ubuntu Package &quot;lxc-docker&quot;" target="_blank"><em>lxc-docker</em></a>.</p>
<p>If you don&#8217;t want extra repositories and you don&#8217;t want the latest version, just install <em>docker.io</em> (I recommend you to enable tab-completion of Docker commands in BASH if you install it):</p>
<p></p><pre class="crayon-plain-tag">$ sudo apt-get update
$ sudo apt-get install docker.io
$ source /etc/bash_completion.d/docker.io</pre><p></p>
<p>To validate the installation, type:</p><pre class="crayon-plain-tag">$ sudo docker version
Client version: 1.0.1
Client API version: 1.12
Go version (client): go1.2.1
Git commit (client): 990021a
Server version: 1.0.1
Server API version: 1.12
Go version (server): go1.2.1
Git commit (server): 990021a
$</pre><p></p>
<p>You need to use <strong>sudo</strong> because the <em>docker</em> daemon always runs as the <em>root</em> user, that&#8217;s because the <em>docker</em> daemon binds to a Unix socket (instead of a TCP port, as it happened until version 0.5.2). By default that Unix socket is owned by the user <em>root</em>, so you need to use the <em>docker</em> command with <em>sudo</em>. You can solve it by <a href="http://docs.docker.com/v1.4/installation/ubuntulinux/#giving-non-root-access" title="Giving non-root access" target="_blank">giving non-root access to Docker</a> or, even better, you can <a href="https://docs.docker.com/installation/ubuntulinux/#create-a-docker-group" title="Create a docker group" target="_blank">create a docker group and add users to it</a>.</p>
<p>Otherwise, if you run docker without sudo you will obtain this error message:</p><pre class="crayon-plain-tag">$ docker version
Client version: 1.0.1
Client API version: 1.12
Go version (client): go1.2.1
Git commit (client): 990021a
2015/03/20 11:40:30 Get http:///var/run/docker.sock/v1.12/version: dial unix /var/run/docker.sock: permission denied
$</pre><p></p>
<p>In order to have the latest version, use the <em>lxc-docker</em> package, that is the one maintained by Docker itself.</p>
<p>There is a <a href="https://get.docker.com/ubuntu/" title="Get Docker on Ubuntu" target="_blank">script to install the Docker package on Ubuntu</a>, but I&#8217;d rather to do it manually. But you can try with:</p>
<p></p><pre class="crayon-plain-tag">$ curl -sSL https://get.docker.com/ubuntu/ | sudo sh</pre><p></p>
<p>To install lxc-docker, your APT system have to deal with https (you can if the file <em>/usr/lib/apt/methods/https</em> exists, it you don&#8217;t have it, install the <em><strong>apt-transport-https</strong></em> package)</p>
<p>Then, just add the Docker repository key to the local keychain, and to the apt sources list. Finally, update and install the <em><strong>lxc-docker</strong></em> package:</p>
<p></p><pre class="crayon-plain-tag">$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
$ sudo sh -c "echo deb https://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
$ sudo apt-get update
$ sudo apt-get install lxc-docker</pre><p></p>
<p>Now we have the last version:</p>
<p></p><pre class="crayon-plain-tag">$ sudo docker version
Client version: 1.5.0
Client API version: 1.17
Go version (client): go1.4.1
Git commit (client): a8a31ef
OS/Arch (client): linux/amd64
Server version: 1.5.0
Server API version: 1.17
Go version (server): go1.4.1
Git commit (server): a8a31ef
$</pre><p></p>
<p>And we can run the basic example, that downloads the <em>ubuntu</em> image, and then start <em>bash</em> in a container. When you&#8217;re done, type <em>exit</em>.</p>
<p></p><pre class="crayon-plain-tag">$ sudo docker run -i -t ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
511136ea3c5a: Pull complete 
f3c84ac3a053: Pull complete 
511136ea3c5a: Download complete 
f3c84ac3a053: Download complete 
a1a958a24818: Download complete 
9fec74352904: Download complete 
d0955f21bf24: Download complete 
Status: Downloaded newer image for ubuntu:latest
root@0f5e5a64c583:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr
root@0f5e5a64c583:/# exit
exit
$</pre><p></p>
<p>Having said that, Docker has changed the instructions for <a href="https://docs.docker.com/installation/ubuntulinux/#installing-docker-on-ubuntu" title="Installing Docker on Ubuntu" target="_blank">Installing Docker on Ubuntu</a>&#8230; today! <img src="http://malsolo.com/blog4java/wp-includes/images/smilies/icon_neutral.gif" alt=":|" class="wp-smiley" /></p>
<p>It seems easier, but I don’t like it very much. If you have wget installed, you can get the latest Docker package with:</p>
<p></p><pre class="crayon-plain-tag">$ wget -qO- https://get.docker.com/ | sh</pre><p></p>
<p>It prompts for the password and then it downloads and installs&#8230; the <em>lxc-docker</em> package. </p>
<p>And then, verify the installation with:</p>
<p></p><pre class="crayon-plain-tag">$ sudo docker run hello-world
[sudo] password for Javier: 
Unable to find image 'hello-world:latest' locally
31cbccb51277: Pull complete 
e45a5af57b00: Pull complete 
511136ea3c5a: Already exists 
hello-world:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security.
Status: Downloaded newer image for hello-world:latest
Hello from Docker.
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (Assuming it was not already locally available.)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

For more examples and ideas, visit:
 http://docs.docker.com/userguide/
$</pre><p></p>
<h1>Using Docker</h1>
<h2>Running applications inside containers</h2>
<p>Docker allows you to run applications inside containers with the command <strong><em>docker run</em></strong>.</p>
<p>The command <em>docker run</em> creates a new container from the image name that you specify (the mandatory parameter for <em>run</em>) and then runs the command in it by performing these steps: Docker looks for the image in this computer, if it isn&#8217;t installed yet, Docker searches the image at Docker Hub to download it and install it. Once the image is installed, Docker creates a new container and starts the program.</p>
<p>We&#8217;ve seen above one example:</p>
<p></p><pre class="crayon-plain-tag">$ sudo docker run -t -i ubuntu:14.04.2 /bin/bash</pre><p></p>
<p>It creates a container from the <a href="https://registry.hub.docker.com/_/ubuntu/" title="Docker Hub: Official Ubuntu base image" target="_blank">Official Ubuntu base image</a> (tag 14.04.2) and then it runs a Bash shell command, with a terminal assigned (flag <strong>-t</strong>), and grabs the standard in of the container(flag <strong>-i</strong>)</p>
<p>For executing in the background (or daemonized), use the <strong>-d</strong> flag:</p>
<p></p><pre class="crayon-plain-tag">$ sudo docker run -d --name="Javier" ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
e84ae64138881b9eaf6ac743c6f0076cfc414f017daef9e59c3d2e1d591eb7b9</pre><p></p>
<p>Here, the command will run forever. Besides, I have assigned a name to the container (OK, my very name, some egocentricity here) to easily discover it later (Docker automatically names any containers that you start, but I&#8217;d rather to specify the name by myself). Furthermore, Docker returns the container ID (<em>e84ae6413888&#8230;</em>).</p>
<p>You can find both the ID and the name when listing containers with the command <em><strong>docker ps</strong></em> (flag <strong>-a</strong> to show all regardless they are running or not)</p>
<p></p><pre class="crayon-plain-tag">$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
e84ae6413888        ubuntu:14.04        "/bin/sh -c 'while t   5 days ago          Up 2 minutes                            Javier              
$</pre><p></p>
<p>The <strong>ports</strong> in the container can be exposed randomly with the <strong>-P</strong> flag or manually with <strong>-p</strong>. In any case, you can see in the column <em>PORTS</em> of the <em>docker ps</em> command or with the <em>docker port</em> command. Let&#8217;s see an example with a <a href="https://registry.hub.docker.com/u/training/webapp/" title="The Docker Fundamentals repository contains the example Hello World Python WebApp" target="_blank">sample web application image</a>.</p>
<p></p><pre class="crayon-plain-tag">$ sudo docker run -d -P training/webapp python app.py
Unable to find image 'training/webapp:latest' locally
Pulling repository training/webapp
31fa814ba25a: Download complete 
511136ea3c5a: Download complete 
f10ebce2c0e1: Download complete 
82cdea7ab5b5: Download complete 
5dbd9cb5a02f: Download complete 
74fe38d11401: Download complete 
64523f641a05: Download complete 
0e2afc9aad6e: Download complete 
e8fc7643ceb1: Download complete 
733b0e3dbcee: Download complete 
a1feb043c441: Download complete 
e12923494f6a: Download complete 
a15f98c46748: Download complete 
Status: Downloaded newer image for training/webapp:latest
a03ec94ea8087789d605ca91d6689d8026e7806e9138b8b9b7ed7f5a1295db85
$ sudo docker ps
CONTAINER ID        IMAGE                    COMMAND             CREATED             STATUS              PORTS                     NAMES
a03ec94ea808        training/webapp:latest   "python app.py"     25 seconds ago      Up 24 seconds       0.0.0.0:49153->5000/tcp   happy_pare          
$ sudo docker port happy_pare
5000/tcp -> 0.0.0.0:49153
$ curl http://localhost:49153
Hello world!
$</pre><p></p>
<p>This means that you can access the application running in the container by using the port 49153 locally.</p>
<p>To manage the container, you can use the next commands:</p>
<ul>
<li><em><strong>docker logs</strong></em> to see the standard output of a container (<strong>-f</strong> to view the new additions, press Ctrl+C to exit)</li>
<li><em><strong>docker top</strong></em> to see the process in the container.</li>
<li><em><strong>docker inspect</strong></em> to see configuration and status information about a container.</li>
<li><em><strong>docker stop/kill</strong></em> to stop or kills (respectively) a running container.</li>
<li><em><strong>docker start</strong></em> to restart a stopped container (remember the command <em>docker ps -a</em>).</li>
<li><em><strong>docker rm</strong></em> to remove a container.</li>
<li><em><strong>docker version</strong></em> to see the current version of the program, its programming language (<a href="https://golang.org/" title="The Go Programming Language" target="_blank">Go</a>) and so on.</li>
</ul>
<p></p><pre class="crayon-plain-tag">$ sudo docker logs happy_pare
 * Running on http://0.0.0.0:5000/
172.17.42.1 - - [31/Mar/2015 09:51:38] "GET / HTTP/1.1" 200 -
$ sudo docker stop happy_pare
happy_pare
$ sudo docker start happy_pare
happy_pare
$ sudo docker kill happy_pare
happy_pare
$ sudo docker rm happy_pare
happy_pare
$ sudo docker top happy_pare
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                8580                1372                0                   12:00               ?                   00:00:00            python app.py
$ sudo docker inspect hungry_kirch
[{
    "AppArmorProfile": "",
    "Args": [
        "app.py"
    ],
    "Config": {
        "AttachStderr": false,
        "AttachStdin": false,
        "AttachStdout": false,
        "Cmd": [
            "python",
            "app.py"
        ],
        "CpuShares": 0,
        "Cpuset": "",
        "Domainname": "",
        "Entrypoint": null,
        "Env": [
            "HOME=/",
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
        ],
        "ExposedPorts": {
            "5000/tcp": {}
        },
        "Hostname": "468cd593eada",
        "Image": "training/webapp",
        "MacAddress": "",
        "Memory": 0,
        "MemorySwap": 0,
        "NetworkDisabled": false,
        "OnBuild": null,
        "OpenStdin": false,
        "PortSpecs": null,
        "StdinOnce": false,
        "Tty": false,
        "User": "",
        "Volumes": null,
        "WorkingDir": "/opt/webapp"
    },
    "Created": "2015-03-31T10:00:32.697111567Z",
    "Driver": "aufs",
    "ExecDriver": "native-0.2",
    "ExecIDs": null,
    "HostConfig": {
        "Binds": null,
        "CapAdd": null,
        "CapDrop": null,
        "ContainerIDFile": "",
        "Devices": [],
        "Dns": null,
        "DnsSearch": null,
        "ExtraHosts": null,
        "IpcMode": "",
        "Links": null,
        "LxcConf": [],
        "NetworkMode": "bridge",
        "PidMode": "",
        "PortBindings": {},
        "Privileged": false,
        "PublishAllPorts": true,
        "ReadonlyRootfs": false,
        "RestartPolicy": {
            "MaximumRetryCount": 0,
            "Name": ""
        },
        "SecurityOpt": null,
        "VolumesFrom": null
    },
    "HostnamePath": "/var/lib/docker/containers/468cd593eadaea6d18441a33ca6c1ea42f1b398d6fd028fa5b557181a5cf36f3/hostname",
    "HostsPath": "/var/lib/docker/containers/468cd593eadaea6d18441a33ca6c1ea42f1b398d6fd028fa5b557181a5cf36f3/hosts",
    "Id": "468cd593eadaea6d18441a33ca6c1ea42f1b398d6fd028fa5b557181a5cf36f3",
    "Image": "31fa814ba25ae3426f8710df7a48d567d4022527ef2c14964bb8bc45e653417c",
    "MountLabel": "",
    "Name": "/hungry_kirch",
    "NetworkSettings": {
        "Bridge": "docker0",
        "Gateway": "172.17.42.1",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "IPAddress": "172.17.0.10",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "LinkLocalIPv6Address": "fe80::42:acff:fe11:a",
        "LinkLocalIPv6PrefixLen": 64,
        "MacAddress": "02:42:ac:11:00:0a",
        "PortMapping": null,
        "Ports": {
            "5000/tcp": [
                {
                    "HostIp": "0.0.0.0",
                    "HostPort": "49155"
                }
            ]
        }
    },
    "Path": "python",
    "ProcessLabel": "",
    "ResolvConfPath": "/var/lib/docker/containers/468cd593eadaea6d18441a33ca6c1ea42f1b398d6fd028fa5b557181a5cf36f3/resolv.conf",
    "RestartCount": 0,
    "State": {
        "Error": "",
        "ExitCode": 0,
        "FinishedAt": "0001-01-01T00:00:00Z",
        "OOMKilled": false,
        "Paused": false,
        "Pid": 8580,
        "Restarting": false,
        "Running": true,
        "StartedAt": "2015-03-31T10:00:32.898205331Z"
    },
    "Volumes": {},
    "VolumesRW": {}
}
]
$</pre><p></p>
<h2>Working with Docker Images</h2>
<p>As we have explained, Docker runs container by using images that are either installed in your system or exists at <a href="https://hub.docker.com/" title="Docker Hub" target="_blank">Docker Hub</a> (in order to download it and install in your system)</p>
<p>You can see what images are already installed with the <strong><em>docker images</em></strong> command.  </p>
<p></p><pre class="crayon-plain-tag">$ sudo docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu                  trusty-20150320     d0955f21bf24        11 days ago         188.3 MB
ubuntu                  14.04               d0955f21bf24        11 days ago         188.3 MB
ubuntu                  14.04.2             d0955f21bf24        11 days ago         188.3 MB
ubuntu                  latest              d0955f21bf24        11 days ago         188.3 MB
ubuntu                  trusty              d0955f21bf24        11 days ago         188.3 MB
training/webapp         latest              31fa814ba25a        10 months ago       278.8 MB
$</pre><p></p>
<p>If you want to manually install an image before running it, you can use the <strong><em>docker pull</em></strong> command for images that you can find at <a href="https://hub.docker.com/" title="Docker Hub" target="_blank">Docker Hub</a> or with the command <strong><em>docker search</em></strong>. </p>
<p>As a curiosity, if you look for images at Docker Hub, you can find Official repos, for instance, the <a href="Java OFFICIAL REPO" title="https://registry.hub.docker.com/_/java/" target="_blank">Java OFFICIAL REPO</a>.</p>
<p>You can add a new name to the image with the <strong><em>docker tag</em></strong>.</p>
<p>If you want to remove an image, you can do so with the <strong><em>docker rmi</em></strong> command.</p>
<h3>A note about the official images</h3>
<p>The images and relevant files are maintained at GitHub by an organization called <a href="https://github.com/docker-library" title="docker-library" target="_blank">docker-library</a> (Docker is open source, and it&#8217;s maintained at GitHub by an organization called <a href="https://github.com/docker" title="Docker" target="_blank">Docker</a>, that has several repositories, including the one for <a href="https://github.com/docker/docker" title="Docker - the open-source application container engine" target="_blank">docker</a>).</p>
<p>The official images exist in a repository, <a href="https://github.com/docker-library/official-images" title="Docker Official Images" target="_blank">Docker Official Images</a>, that contains a folder for the <a href="https://github.com/docker-library/official-images/tree/master/library" title="official-images/library" target="_blank">library definitions</a>, for instance, the one for <a href="https://github.com/docker-library/official-images/blob/master/library/java" title="official-images/library/java" target="_blank">java</a>.</p>
<p>The image packages are also maintained by docker-library in each corresponding repository, for instance, the <a href="https://github.com/docker-library/java" title="Docker Official Image packaging for Java (openJDK)" target="_blank">Docker Official Image packaging for Java</a> (<a href="http://openjdk.java.net/" title="OpenJDK" target="_blank">openJDK</a>)</p>
<p>It&#8217;s worth to mention it because there is another organization at GitHub called <a href="https://github.com/dockerfile" title="Dockerfile Project" target="_blank"></a> (<em>Trusted Automated Docker Builds</em>) that has repositories for several Docker builds, for instance, the one for <a href="https://github.com/dockerfile/java" title="Java Dockerfile for trusted automated Docker builds" target="_blank">Java</a>, that includes an image for <a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html" title="Java SE Development Kit 8 Downloads" target="_blank">Oracle Java 8 JDK</a> (that I was looking for) </p>
<h3>Creating your own images</h3>
<p>There are two ways for updating and creating images.</p>
<ol>
<li>Run a container from an image (<em>docker run</em>), then update it, and finally commit the results to an image, with the <em><strong>docker commit</strong></em> command.</li>
<li>Use a <em><strong>Dockerfile</strong></em> to create an image.</li>
</ol>
<p>When you&#8217;re done, you can push the created image to Docker Hub with the <strong><em>docker push</em></strong> command.</p>
<p>Finally, you can remove images with the <strong><em>docker rmi</em></strong> command.</p>
<p></p><pre class="crayon-plain-tag">$ sudo docker run -t -i ubuntu:latest /bin/bash
root@98bec5327540:/# sudo apt-get install --reinstall software-properties-common
root@98bec5327540:/# sudo add-apt-repository ppa:webupd8team/java
root@98bec5327540:/# sudo apt-get update
root@98bec5327540:/# sudo apt-get install oracle-java8-installer
root@98bec5327540:/# sudo apt-get install nano
root@98bec5327540:/# wget http://apache.rediris.es/maven/maven-3/3.3.1/binaries/apache-maven-3.3.1-bin.tar.gz
root@98bec5327540:/# tar -xvf apache-maven-3.3.1-bin.tar.gz 
root@98bec5327540:/# cp -r apache-maven-3.3.1 /usr/local/apache-maven
root@98bec5327540:/# sudo nano /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/apache-maven/bin"
JAVA_HOME="/usr/lib/jvm/java-8-oracle"
MAVEN_OPTS="-Xms256m -Xmx512m"
root@98bec5327540:/# source /etc/environment 
root@98bec5327540:/# echo $JAVA_HOME
/usr/lib/jvm/java-8-oracle
root@98bec5327540:/# java -version
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b25)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
root@98bec5327540:/# mvn -version
Apache Maven 3.3.1 (cab6659f9874fa96462afef40fcf6bc033d58c1c; 2015-03-13T20:10:27+00:00)
Maven home: /usr/local/apache-maven
Java version: 1.8.0_40, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-8-oracle/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "3.13.0-48-generic", arch: "amd64", family: "unix"
root@98bec5327540:/# exit
$ sudo docker ps -a
CONTAINER ID        IMAGE                    COMMAND                CREATED             STATUS                        PORTS               NAMES
98bec5327540        ubuntu:14.04             "/bin/bash"            47 minutes ago      Exited (0) 4 minutes ago                          determined_carson   
468cd593eada        training/webapp:latest   "python app.py"        2 hours ago         Exited (137) 2 minutes ago                        hungry_kirch        
e84ae6413888        ubuntu:14.04             "/bin/sh -c 'while t   5 days ago          Exited (137) 3 hours ago                          Javier              
0f5e5a64c583        ubuntu:14.04             "/bin/bash"            11 days ago         Exited (0) 11 days ago                            dreamy_hopper     

$ sudo docker commit -m "Ubuntu latest (14.04) with  Oracle Java 8 JDK and Apache Maven 3.3.1 (and nano editor)" -a "Javier Beneito Barquero" 98bec5327540 jbbarquero/ubuntu-java8_oracle-maven
e262639379c46afa53eca74de9df9bd2f81e0ab7839a3472cafb67d7e199d85e
$

$ sudo docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
jbbarquero/ubuntu-java8_oracle-maven   latest              e262639379c4        56 seconds ago      828 MB
ubuntu                                 14.04               d0955f21bf24        11 days ago         188.3 MB
ubuntu                                 14.04.2             d0955f21bf24        11 days ago         188.3 MB
ubuntu                                 latest              d0955f21bf24        11 days ago         188.3 MB
ubuntu                                 trusty              d0955f21bf24        11 days ago         188.3 MB
ubuntu                                 trusty-20150320     d0955f21bf24        11 days ago         188.3 MB
centos                                 latest              88f9454e60dd        3 weeks ago         210 MB
hello-world                            latest              e45a5af57b00        12 weeks ago        910 B
training/webapp                        latest              31fa814ba25a        10 months ago       278.8 MB
$ sudo docker tag jbbarquero/ubuntu-java8_oracle-maven my-java8
$ sudo docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
jbbarquero/ubuntu-java8_oracle-maven   latest              e262639379c4        About a minute ago   828 MB
my-java8                               latest              e262639379c4        About a minute ago   828 MB
ubuntu                                 trusty-20150320     d0955f21bf24        11 days ago          188.3 MB
ubuntu                                 14.04               d0955f21bf24        11 days ago          188.3 MB
ubuntu                                 14.04.2             d0955f21bf24        11 days ago          188.3 MB
ubuntu                                 latest              d0955f21bf24        11 days ago          188.3 MB
ubuntu                                 trusty              d0955f21bf24        11 days ago          188.3 MB
centos                                 latest              88f9454e60dd        3 weeks ago          210 MB
hello-world                            latest              e45a5af57b00        12 weeks ago         910 B
training/webapp                        latest              31fa814ba25a        10 months ago        278.8 MB

$ sudo docker run -t -i my-java8 /bin/bash
root@da1045b88138:/# mvn -version
Apache Maven 3.3.1 (cab6659f9874fa96462afef40fcf6bc033d58c1c; 2015-03-13T20:10:27+00:00)
Maven home: /usr/local/apache-maven
Java version: 1.8.0_40, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-8-oracle/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "3.13.0-48-generic", arch: "amd64", family: "unix"
root@da1045b88138:/# exit
exit
$ 

$ sudo docker push jbbarquero/ubuntu-java8_oracle-maven
The push refers to a repository [jbbarquero/ubuntu-java8_oracle-maven] (len: 1)
Sending image list

Please login prior to push:
Username: jbbarquero
Password: 
Email: jbbarquero@gmail.com
Login Succeeded
The push refers to a repository [jbbarquero/ubuntu-java8_oracle-maven] (len: 1)
Sending image list
Pushing repository jbbarquero/ubuntu-java8_oracle-maven (1 tags)
511136ea3c5a: Image already pushed, skipping 
f3c84ac3a053: Image already pushed, skipping 
a1a958a24818: Image already pushed, skipping 
9fec74352904: Image already pushed, skipping 
d0955f21bf24: Image already pushed, skipping 
e262639379c4: Image successfully pushed 
Pushing tag for rev [e262639379c4] on {https://cdn-registry-1.docker.io/v1/repositories/jbbarquero/ubuntu-java8_oracle-maven/tags/latest}
$</pre><p></p>
<p>You can find this image at <a href="https://registry.hub.docker.com/u/jbbarquero/ubuntu-java8_oracle-maven/" title="jbbarquero / ubuntu-java8_oracle-maven" target="_blank">jbbarquero / ubuntu-java8_oracle-maven</a></p>
<p>How to <a href="https://docs.docker.com/reference/builder/" title="Dockerfile Reference" target="_blank">write a Dockerfile</a> is out of the bounds of this first post, but I can create a very basic one. Just for fun.</p>
<p>Having this Dockerfile:</p>
<p></p><pre class="crayon-plain-tag"># This is a comment
FROM jbbarquero/ubuntu-java8_oracle-maven
MAINTAINER Javier Beneito Barquero &lt;jbbarquero@gmail.com&gt;
RUN apt-get update &amp;&amp; apt-get install -y git</pre><p></p>
<p>Just build it (and then push it)</p>
<p></p><pre class="crayon-plain-tag">$ sudo docker build -t jbbarquero/ubuntu-java8_oracle-maven-git .
Sending build context to Docker daemon 2.048 kB
Sending build context to Docker daemon 
Step 0 : FROM jbbarquero/ubuntu-java8_oracle-maven
 ---> e262639379c4
Step 1 : MAINTAINER Javier Beneito Barquero <jbbarquero@gmail.com>
 ---> Running in d1be5fc2ed6e
 ---> 162fdb8b3a3d
Removing intermediate container d1be5fc2ed6e
Step 2 : RUN apt-get update && apt-get install -y git
 ---> Running in b7c2cf318638

... Lot of installation messages here

 ---> f63b88cf14ab
Removing intermediate container b7c2cf318638
Successfully built f63b88cf14ab
$ sudo docker images
REPOSITORY                                 TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
jbbarquero/ubuntu-java8_oracle-maven-git   latest              f63b88cf14ab        17 seconds ago      876.5 MB
...

$ sudo docker run -t -i jbbarquero/ubuntu-java8_oracle-maven-git /bin/bash
root@bb9caa298372:/# git --version
git version 1.9.1
root@bb9caa298372:/# mvn -version
Apache Maven 3.3.1 (cab6659f9874fa96462afef40fcf6bc033d58c1c; 2015-03-13T20:10:27+00:00)
Maven home: /usr/local/apache-maven
Java version: 1.8.0_40, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-8-oracle/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "3.13.0-48-generic", arch: "amd64", family: "unix"
root@bb9caa298372:/# exit
exit</pre><p></p>
<p>The new image can be found in Docker Hub, find it at <a href="https://registry.hub.docker.com/u/jbbarquero/ubuntu-java8_oracle-maven-git/http://" title="jbbarquero / ubuntu-java8_oracle-maven-git" target="_blank">jbbarquero / ubuntu-java8_oracle-maven-git</a>.</p>
<h1>Closing words</h1>
<p>That&#8217;s enough for now. There are a couple of interesting topics, but we&#8217;ll leave for another time:</p>
<ul>
<li><a href="https://docs.docker.com/userguide/dockerlinks/" title="Linking Containers Together" target="_blank">Linking Containers</a>, for sending information between containers in Docker.</li>
<li><a href="https://docs.docker.com/userguide/dockervolumes/" title="Managing Data in Containers" target="_blank">Data in containers</a>, for managing data volumes.</li>
</ul>
<h1>Resources</h1>
<ul>
<li><a href="https://docs.docker.com/" title="Docker docs" target="_blank">Docker official documentation</a></li>
<li><a href="https://www.docker.com/tryit/" title="Docker, try it!" target="_blank">Docker 10-minute tutorial</a></li>
<li><a href="https://docs.docker.com/installation/ubuntulinux/" title="Docker installation: Ubuntu" target="_blank">Docker installation: Ubuntu</a></li>
<li><a href="http://www.manning.com/nickoloff/" title="Docker in Action" target="_blank">Docker in Action</a>. By Jeff Nickoloff (Manning)</li>
<li><a href="http://www.manning.com/miell/" title="Docker in Practice" target="_blank">Docker in Practice</a>. By Ian Miell and Aidan Hobson Sayers (Manning)</li>
</li>
<li><a href="http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html" title="install oracle java 8 in ubuntu via ppa repository [jdk8]" target="_blank">Install oracle java 8 in ubuntu via ppa repository [jdk8]</a></li>
<li><a href="http://askubuntu.com/questions/38021/how-to-add-a-ppa-on-a-server" title="How to add a PPA on a server?" target="_blank">How to add a PPA on a server?</a></li>
<li><a href="https://help.ubuntu.com/community/Nano" title="Nano" target="_blank">Nano at Ubuntu</a></li>
<li><a href="https://maven.apache.org/download.cgi" title="Download Apache Maven 3.3.1" target="_blank">Download Apache Maven 3.3.1</a></li>
</ul>
<h1>Post scríptum</h1>
<p>When re-starting the container jbbarquero/ubuntu-java8_oracle-maven, <em>source /etc/environment</em> is not called, so the values that I wrote there are not applied. For solving this issue, I edited /etc/bash.bashrc and I put there the environment variables.</p>
<p></p><pre class="crayon-plain-tag">root@98bec5327540:/# sudo nano /etc/bash.bashrc
$ sudo docker start -i 98bec5327540
root@98bec5327540:/# sudo nano /etc/bash.bashrc

JAVA_HOME="/usr/lib/jvm/java-8-oracle"
export JAVA_HOME

M2_HOME=/usr/local/apache-maven
export M2_HOME
M2=$M2_HOME/bin
export M2

PATH=$PATH:$JAVA_HOME
PATH=$PATH:$M2
export PATH

root@98bec5327540:/# exit</pre><p></p>
<p>Maybe a <strong>Dockerfile</strong> is a better idea to create containers with <a href="https://docs.docker.com/reference/builder/#env" title="Dockerfile Reference: ENV instruction" target="_blank">environment variables using ENV</a>.<br />
so the values that I wrote there</p>
]]></content:encoded>
			<wfw:commentRss>http://malsolo.com/blog4java/?feed=rss2&#038;p=794</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Webinar Confirmation: Java, Ubuntu and browsers hell</title>
		<link>http://malsolo.com/blog4java/?p=812</link>
		<comments>http://malsolo.com/blog4java/?p=812#comments</comments>
		<pubDate>Tue, 24 Mar 2015 09:19:29 +0000</pubDate>
		<dc:creator><![CDATA[Javier (@jbbarquero)]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[Java Plug-in]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://malsolo.com/blog4java/?p=812</guid>
		<description><![CDATA[Hello Javier, Your registration is confirmed for the webinar&#8230; We are looking forward to having you join us. To help maximize your webinar experience we recommend that you join a test meeting before the session to check your system and &#8230; <a href="http://malsolo.com/blog4java/?p=812">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><em>Hello Javier,</p>
<p>Your registration is confirmed for the webinar&#8230; We are looking forward to having you join us.</p>
<p><img src="http://malsolo.com/blog4java/wp-includes/images/smilies/icon_biggrin.gif" alt=":D" class="wp-smiley" /></p>
<p>To help maximize your webinar experience we recommend that you join a test meeting before the session to check your system and browser compatibility at <u>http://www.webex.com/test-meeting.html</u>.</em></p>
<p>Let&#8217;s try&#8230;</p>
<div id="attachment_816" style="width: 969px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-094340.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-094340.png" alt="Java is not working." width="959" height="511" class="size-full wp-image-816" /></a><p class="wp-caption-text">Java is not working.</p></div>
<p>Dammit!</p>
<p>Now I have to waste half an hour for discovering the problem and solve it.</p>
<p>Let&#8217;s see, <a href="https://java.com/en/download/faq/chrome.xml" title="How do I use Java with the Google Chrome browser?" target="_blank">How do I use Java with the Google Chrome browser?</a></p>
<p><em><strong>Chrome and Linux</strong><br />
Starting with Chrome version 35, NPAPI (Netscape Plug-in API) support was removed for the Linux platform. For more information, see Chrome and NPAPI (<a href="http://blog.chromium.org/2013/09/saying-goodbye-to-our-old-friend-npapi.html" title="Saying Goodbye to Our Old Friend NPAPI" target="_blank">blog.chromium.org</a>).</p>
<p><u>Firefox is the recommended browser for Java on Linux.</u></em></p>
<p>No problem, let&#8217;s use Firefox. But&#8230;</p>
<div id="attachment_814" style="width: 761px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-094112.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-094112.png" alt="Expired or not-yet-valid certificate" width="751" height="364" class="size-full wp-image-814" /></a><p class="wp-caption-text">Java Security</p></div>
<p>Sometimes I miss Windows and its closed environment.</p>
<p>Don&#8217;t give up. In the error page, the details shows the Java Console:</p>
<div id="attachment_818" style="width: 529px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-094812.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-094812.png" alt="Java Console screenshot" width="519" height="434" class="size-full wp-image-818" /></a><p class="wp-caption-text">Java Plug-in 11.40.2.25</p></div>
<p>And the <a href="http://java.com/en/download/help/jcp_security.xml" title="How do I control when an untrusted applet or application runs in my web browser? " target="_blank">more information</a> link leads to the instructions to handle the Java Security via the Control Panel. Including a link to the configuration of the <a href="http://java.com/en/download/faq/exception_sitelist.xml" title="How can I configure the Exception Site List? " target="_blank">Exception Site List</a>.</p>
<p>But&#8230;</p>
<p><em><strong>Find the Java Control Panel</strong><br />
» <a href="http://java.com/en/download/help/win_controlpanel.xml" title="Where is the Java Control Panel on Windows? " target="_blank">Windows</a><br />
» <a href="http://java.com/en/download/help/mac_controlpanel.xml" title="Where is the Java Control Panel on my Mac? " target="_blank">Mac OS X</a></em> </p>
<p><strong>Where is the Java Control Panel on Linux?!!!</strong> <img src="http://malsolo.com/blog4java/wp-includes/images/smilies/icon_neutral.gif" alt=":|" class="wp-smiley" /></p>
<p><u>Keep calm and open the Terminal</u>:</p>
<p></p><pre class="crayon-plain-tag">$ whereis java
java: /usr/bin/java
$ ls -la /usr/bin/java
lrwxrwxrwx 1 root root 22 may  8  2014 /usr/bin/java -> /etc/alternatives/java
$ cd /usr/lib/jvm/java-8-oracle/jre/bin
$ ls
ControlPanel  javaws.real  keytool  policytool   servertool
java          jcontrol     orbd     rmid         tnameserv
javaws        jjs          pack200  rmiregistry  unpack200
$ ./ControlPanel</pre><p></p>
<p>Now, you can follow the instructions:</p>
<div id="attachment_821" style="width: 637px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-095904.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-095904.png" alt="Java Control Panel" width="627" height="641" class="size-full wp-image-821" /></a><p class="wp-caption-text">Java Control Panel</p></div>
<p>Go to the Security tab:</p>
<div id="attachment_822" style="width: 637px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-095934.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-095934.png" alt="Java Control Panel: Security tab" width="627" height="641" class="size-full wp-image-822" /></a><p class="wp-caption-text">Java Control Panel: Security tab</p></div>
<p>Press Edit <u>S</u>ite List&#8230;</p>
<div id="attachment_823" style="width: 560px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-100040.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-100040.png" alt="Exception Site List" width="550" height="379" class="size-full wp-image-823" /></a><p class="wp-caption-text">Exception Site List</p></div>
<p>Add the location:</p>
<div id="attachment_824" style="width: 560px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-100150.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-100150.png" alt="Exception Site List: add URL" width="550" height="379" class="size-full wp-image-824" /></a><p class="wp-caption-text">Exception Site List: add URL</p></div>
<p>Ok. Ok.</p>
<p>Now re-try:</p>
<div id="attachment_825" style="width: 604px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-100356.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-100356.png" alt="I&#039;m really tired" width="594" height="463" class="size-full wp-image-825" /></a><p class="wp-caption-text">I&#8217;m really tired</p></div>
<p>I&#8217;ve spent too much time with you, so <em>I accept the risk</em> <img src="http://malsolo.com/blog4java/wp-includes/images/smilies/icon_sad.gif" alt=":(" class="wp-smiley" /></p>
<div id="attachment_826" style="width: 630px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-100624.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/03/Screenshot-from-2015-03-24-100624-1024x576.png" alt="Horray!" width="620" height="349" class="size-large wp-image-826" /></a><p class="wp-caption-text">Horray!</p></div>
<p>Piece of cake.</p>
<p>It&#8217;s been fun and annoying at the same time.</p>
]]></content:encoded>
			<wfw:commentRss>http://malsolo.com/blog4java/?feed=rss2&#038;p=812</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting started with Spark</title>
		<link>http://malsolo.com/blog4java/?p=679</link>
		<comments>http://malsolo.com/blog4java/?p=679#comments</comments>
		<pubDate>Mon, 02 Mar 2015 15:27:16 +0000</pubDate>
		<dc:creator><![CDATA[Javier (@jbbarquero)]]></dc:creator>
				<category><![CDATA[Big Data]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Hadoop]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Spark]]></category>

		<guid isPermaLink="false">http://malsolo.com/blog4java/?p=679</guid>
		<description><![CDATA[Spark Introduction Apache Spark is a cluster computing platform designed to be fast, expresive, high level, general-purpose, fault-tolerante and compatible with Hadoop (Spark can work directly with HDFS, S3 and so on). Spark can also be defined as a framework &#8230; <a href="http://malsolo.com/blog4java/?p=679">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<h1>Spark Introduction</h1>
<p>Apache Spark is a cluster <strong>computing platform</strong> designed to be fast, expresive, high level, general-purpose, fault-tolerante and compatible with Hadoop (Spark can work directly with HDFS, S3 and so on). Spark can also be defined as a framework for distributed processing and analisys of big amounts of data. People from databricks (the company behind Spark) called it a distributed executing engine for large scale analytics.</p>
<p>Spark improves efficiency over Hadoop because it uses in-memory computing primitives. According to the <a title="Apache Spark™" href="https://spark.apache.org/" target="_blank">Apache Spark site</a>, it can run programs up to 100x faster than Hadoop MapReduce in memory, or 10x faster on disk.</p>
<p>It also claims to improve usability through rich Scala, Python and Java APIs as well as an interactive shell, in Scala and Python. Spark is written in Scala.</p>
<h2>Spark Architecture</h2>
<p>Spark has three main components</p>
<div id="attachment_688" style="width: 630px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/02/apache_spark_stack.png"><img class="size-large wp-image-688" src="http://malsolo.com/blog4java/wp-content/uploads/2015/02/apache_spark_stack-1024x534.png" alt="The Apache Spark stack" width="620" height="323" /></a><p class="wp-caption-text">Apache Spark stack</p></div>
<h3>Spark Core (API)</h3>
<p>A high level programming framework that allows programmers to focus on the logic and not the plumbing of distributing programming, that is, the steps to be done without worrying of coordinating tasks, networking of so on.</p>
<p>These steps are define by RDD (Resilient Distributed Datasets), the main programming abstraction that represent a collection of items distributed across many compute nodes that can be manipulated in parallel.</p>
<h3>Spark clustering</h3>
<p>Spark itself doesn&#8217;t manage the cluster, but it supports three cluster managers:</p>
<ul>
<li>Standalone: a simple cluster manager included in Spark itself called the Standalone Scheduler.</li>
<li><a title="Apache Hadoop YARN" href="http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/YARN.html" target="_blank">Hadoop YARN</a>: see my <a title=" Getting started with Hadoop" href="http://malsolo.com/blog4java/?p=516" target="_blank">introduction to Apache Hadoop</a>.</li>
<li><a title="Apache Mesos" href="http://mesos.apache.org/" target="_blank">Apache Mesos</a>.</li>
</ul>
<h3>Spark stack</h3>
<p>Finally, Spark provides high level specialized components that are closely integrated in order to provide one great platform.</p>
<p>The current components are:</p>
<ul>
<li>Spark SQL: for querying data via SQL.</li>
<li>Spark Streaming: for real-time processing of live streams of data.</li>
<li>GraphX: a library for manipulating graphs and performing graph-parallel computations.</li>
<li>MLLib: a library for machine learning providing algorithms for doing so (classification, regression, &#8230;)</li>
</ul>
<h2>Spark Usage</h2>
<p>There are two ways to work with Spark:</p>
<ul>
<li>The Spark interactive shells</li>
<li>Spark standalone applications</li>
</ul>
<h3>Spark Shell</h3>
<p>It&#8217;s an interactive shell from the command line that has two implementations, one in Python and the other in Scala, an <a title="RPEL: Read–eval–print loop" href="http://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop" target="_blank">RPEL</a> that is very useful for learning the API or for data exploration.</p>
<p>Spark’s shells allow you to interact with data not only on your single machine, but on disk or in memory across many machines, thanks to the distributed nature of Spark.</p>
<h3>Spark Applications</h3>
<p>The other way to work with Spark is by creating standalone applications either in Python, Scala or Java. Use them for large scale data processing.</p>
<h2>Spark main concepts</h2>
<h3>Driver program</h3>
<p>It&#8217;s the program that launches the distributed operations on a cluster.</p>
<p>The Spark shell is a driver program.</p>
<p>The application that you write, with its <em>main</em> function that defines de datasets and applies operations on them is a driver program.</p>
<h3>Spark Context (sc)</h3>
<p>It&#8217;s the main entry point to the Spark API.</p>
<p>When using the shell, a preconfigured SparkContext is automatically created and it&#8217;s available in the variable called <strong><em>sc</em></strong>.</p>
<p>When writing applications, the first thing that you need to create is your own instance of the SparkContext.</p>
<h3>Resilient Distributed Dataset (RDD)</h3>
<p>The goal of Spark is to allow you to operate in datasets in a single machine and that these operations work in the same way in a distributed cluster.</p>
<p>For achieving this, Spark offers the <strong>Resilient Distributed Dataset</strong> (RDD), they are <span style="text-decoration: underline;">immutable collections</span> (<em>dataset</em>) of objects that Spark distributes (<em>distributed</em>) through the cluster. They are loaded from a source of data and, since they are immutable, RDDs are also created as a result of transformation on existing RDDs (map, filters, etc.). Finally, Spark automatically rebuilds them in a node if there is a failure in another node (<em>resilient</em>)</p>
<p>There are two types of RDD operations on RDDs:</p>
<ul>
<li><strong>Transformations</strong>: lazy operations to build RDDs based on the current RDD.</li>
<li><strong>Actions</strong>: return a result or write the RDD to storage. It implies a computation that actually applies the pending transformation that were lazily defined.</li>
</ul>
<p>In the Spark jargon, this is called a Direct Acyclic Graph (DAG) of operations. The RDDs track the series of transformations used to build them by maintaining a pointer to its parents.</p>
<h1>Spark Installation</h1>
<p>Go to <a title="Download Spark" href="https://spark.apache.org/downloads.html" target="_blank">https://spark.apache.org/downloads.html</a> and then:</p>
<ol>
<li>Choose a Spark release (1.2.1 is the last at the time of this writing)</li>
<li>Choose a package type: select the package type of <em>“Pre-built for Hadoop 2.4 and later”</em></li>
<li>Choose a download type: <em>Direct Download</em> is OK, but the default <em>Apache Mirror</em> works well.</li>
<li>Click on the link after <em>Download Spark</em>, for instance <strong><em>spark-1.2.1.tgz</em></strong>, to download Spark.</li>
</ol>
<p>Unpack the downloaded file and move into that directory in order to use the interactive shell:</p><pre class="crayon-plain-tag">$ tar -xf spark-1.2.0-bin-hadoop2.4.tgz
$ cd spark-1.2.0-bin-hadoop2.4</pre><p></p>
<h2>Using the Shell</h2>
<p>The Python version of the Spark shell is available via the command <strong>bin/pyspark</strong> and the Scala version of the shell by using <strong>bin/spark-shell</strong>.</p>
<p>Note: the shell accept code completion with the Tab key.</p>
<p>Let&#8217;s try the <strong>Scala</strong> shell:</p><pre class="crayon-plain-tag">$ bin/spark-shell
Spark assembly has been built with Hive, including Datanucleus jars on classpath
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
15/02/26 17:23:45 INFO SecurityManager: Changing view acls to: Javier
15/02/26 17:23:45 INFO SecurityManager: Changing modify acls to: Javier
15/02/26 17:23:45 INFO SecurityManager: SecurityManager: authentication disabled; ui acls disabled; users with view permissions: Set(Javier); users with modify permissions: Set(Javier)
15/02/26 17:23:45 INFO HttpServer: Starting HTTP Server
15/02/26 17:23:45 INFO Utils: Successfully started service 'HTTP class server' on port 46130.
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 1.2.1
      /_/

Using Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_31)
Type in expressions to have them evaluated.
Type :help for more information.
15/02/26 17:23:50 WARN Utils: Your hostname, xxx resolves to a loopback address: 127.0.1.1; using 192.168.2.49 instead (on interface eth0)
15/02/26 17:23:50 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address
15/02/26 17:23:50 INFO SecurityManager: Changing view acls to: Javier
15/02/26 17:23:50 INFO SecurityManager: Changing modify acls to: Javier
15/02/26 17:23:50 INFO SecurityManager: SecurityManager: authentication disabled; ui acls disabled; users with view permissions: Set(Javier); users with modify permissions: Set(Javier)
15/02/26 17:23:51 INFO Slf4jLogger: Slf4jLogger started
15/02/26 17:23:51 INFO Remoting: Starting remoting
15/02/26 17:23:51 INFO Remoting: Remoting started; listening on addresses :[akka.tcp://sparkDriver@xxx.malsolo.lan:55248]
15/02/26 17:23:51 INFO Utils: Successfully started service 'sparkDriver' on port 55248.
15/02/26 17:23:51 INFO SparkEnv: Registering MapOutputTracker
15/02/26 17:23:51 INFO SparkEnv: Registering BlockManagerMaster
15/02/26 17:23:52 INFO DiskBlockManager: Created local directory at /tmp/spark-1420fe71-6907-408a-b44c-9547ba1a2c49/spark-909fad01-a3df-484b-bd30-1ea6006396e9
15/02/26 17:23:52 INFO MemoryStore: MemoryStore started with capacity 265.1 MB
15/02/26 17:23:52 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
15/02/26 17:23:52 INFO HttpFileServer: HTTP File server directory is /tmp/spark-82586699-a230-47e4-8148-2cc4dcc741ec/spark-72f09be4-797a-4612-a845-e4fd1e578e76
15/02/26 17:23:52 INFO HttpServer: Starting HTTP Server
15/02/26 17:23:52 INFO Utils: Successfully started service 'HTTP file server' on port 41493.
15/02/26 17:23:53 INFO Utils: Successfully started service 'SparkUI' on port 4040.
15/02/26 17:23:53 INFO SparkUI: Started SparkUI at http://xxx.malsolo.lan:4040
15/02/26 17:23:53 INFO Executor: Starting executor ID  on host localhost
15/02/26 17:23:53 INFO Executor: Using REPL class URI: http://192.168.2.49:46130
15/02/26 17:23:53 INFO AkkaUtils: Connecting to HeartbeatReceiver: akka.tcp://sparkDriver@xxx.malsolo.lan:55248/user/HeartbeatReceiver
15/02/26 17:23:53 INFO NettyBlockTransferService: Server created on 40938
15/02/26 17:23:53 INFO BlockManagerMaster: Trying to register BlockManager
15/02/26 17:23:53 INFO BlockManagerMasterActor: Registering block manager localhost:40938 with 265.1 MB RAM, BlockManagerId(, localhost, 40938)
15/02/26 17:23:53 INFO BlockManagerMaster: Registered BlockManager
15/02/26 17:23:53 INFO SparkILoop: Created spark context..
Spark context available as sc.

scala&gt;</pre><p>To exit either shell, press Ctrl-D.</p><pre class="crayon-plain-tag">scala&gt; Stopping spark context.
15/02/26 17:27:40 INFO SparkUI: Stopped Spark web UI at http://xxx.malsolo.lan:4040
15/02/26 17:27:40 INFO DAGScheduler: Stopping DAGScheduler
15/02/26 17:27:41 INFO MapOutputTrackerMasterActor: MapOutputTrackerActor stopped!
15/02/26 17:27:41 INFO MemoryStore: MemoryStore cleared
15/02/26 17:27:41 INFO BlockManager: BlockManager stopped
15/02/26 17:27:41 INFO BlockManagerMaster: BlockManagerMaster stopped
15/02/26 17:27:41 INFO SparkContext: Successfully stopped SparkContext
15/02/26 17:27:41 INFO RemoteActorRefProvider$RemotingTerminator: Shutting down remote daemon.
15/02/26 17:27:41 INFO RemoteActorRefProvider$RemotingTerminator: Remote daemon shut down; proceeding with flushing remote transports.
15/02/26 17:27:41 INFO RemoteActorRefProvider$RemotingTerminator: Remoting shut down.
$</pre><p>It&#8217;s possible to control the verbosity of the logging by creating a <em>conf/log4j.properties</em> file (use the existing <em>conf/log4j.properties.template</em>, Currently, Spark uses log4j 1.2.17, so you can find more details at <a title="Apache log4j™ 1.2" href="http://logging.apache.org/log4j/1.2/" target="_blank">Apache log4j™ 1.2</a> website.) and then changing the line:</p>
<p><strong>log4j.rootCategory=INFO, console</strong></p>
<p>To:</p>
<p><strong>log4j.rootCategory=WARN, console</strong></p>
<p>Now, with the shell we can try some commands like examining the sc variable, create RDDs, filtering them and so on.</p><pre class="crayon-plain-tag">scala&gt; sc
res0: org.apache.spark.SparkContext = org.apache.spark.SparkContext@76af34b5

scala&gt; val lines = sc.textFile("README.md")
lines: org.apache.spark.rdd.RDD[String] = README.md MappedRDD[1] at textFile at :12

scala&gt; lines.count()
res1: Long = 98                                                                 

scala&gt; lines.first()
res2: String = # Apache Spark</pre><p></p>
<p>There is an INFO message that informs of the URL of the Spark UI (INFO SparkUI: Started SparkUI at http://[ipaddress]:4040), so you can use it to see information about the tasks and clusters.</p>
<div id="attachment_725" style="width: 904px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/03/SparkUI-2.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/03/SparkUI-2.png" alt="Spark UI at 4040" width="894" height="574" class="size-full wp-image-725" /></a><p class="wp-caption-text">Spark UI</p></div>
<h1>Spark Operations</h1>
<p>Once we have the Spark shell, let&#8217;s use it to take a look to the available operations before we dive into creating applications.</p>
<h2>Creating RDDs</h2>
<p>You can turn an existing collection into a RDD (parallelize it), you can load an external file (several formats: text, JSON, CSV, SequenceFiles, objects) or even existing Hadoop InputFormat (with <em>sc.hadoopFile()</em>) </p>
<p></p><pre class="crayon-plain-tag">scala> val numbers = sc.parallelize(List(1,2,3))
numbers: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:12

scala> val lines = sc.textFile("README.md")
lines: org.apache.spark.rdd.RDD[String] = README.md MappedRDD[2] at textFile at <console>:12

scala></pre><p></p>
<h2>Transformations</h2>
<p>As we said earlier, transformations are lazy evaluated operations on RDDs that return a new RDD.</p>
<p>You can pass each element through a function (with <em>map()</em>) or keep elements that pass a predicate (with <em>filter()</em>) or produce zero or more elements for each element (with <em>flatMap()</em>) and so on.</p>
<p></p><pre class="crayon-plain-tag">scala> val squares = numbers.map(x => x*x)
squares: org.apache.spark.rdd.RDD[Int] = MappedRDD[3] at map at <console>:14

scala> val spark = lines.filter(line => line.contains("Spark"))
spark: org.apache.spark.rdd.RDD[String] = FilteredRDD[4] at filter at <console>:14

scala> val sequences = numbers.flatMap(x => 1 to x)
sequences: org.apache.spark.rdd.RDD[Int] = FlatMappedRDD[5] at flatMap at <console>:14

scala> val words = lines.flatMap(line => line.split(" "))
words: org.apache.spark.rdd.RDD[String] = FlatMappedRDD[6] at flatMap at <console>:14

scala></pre><p></p>
<h2>Actions</h2>
<p>They are the operations that return a final value to the driver program or write data to an external storage system that result in the evaluation of the transformations in the RDD.</p>
<p>For instance, retrieve the contents (<em>collect()</em>), return the first n elements (<em>take()</em>), count the number of elements (<em>count()</em>), combine elements with an associative function (<em>reduce()</em>) or write elements to a text file (<em>saveAsTextFile()</em>)</p>
<p></p><pre class="crayon-plain-tag">scala> sequences.collect()
res0: Array[Int] = Array(1, 1, 2, 1, 2, 3)                                      

scala> squares.take(2)
res1: Array[Int] = Array(1, 4)

scala> words.count()
res2: Long = 524

scala> numbers.reduce((x, y) => x + y)
res4: Int = 6

scala> spark.saveAsTextFile("borrar.txt")

scala></pre><p></p>
<h2>Key/Value Pairs</h2>
<p>There is a special type of RDD, <strong>Pair RDDs</strong>, that that contain elements that are tuples, that is, a key-value pair, being key and value of any type.</p>
<p>They are very useful for perform aggregations, grouping, counting. They can be obtained from some initial ETL (extract, transform, load) operations.</p>
<p>The pair RDDS can be partitioned across nodes for improving speed by allowing similar keys to be accesible on the same node.</p>
<p>Regarding operations, Spark offers special operation for Pair RDDs that allow you to act on each key in parallel, for instance, <em>reduceByKey()</em> to aggregate data by key, <em>join()</em> to merge two RDDs by grouping elements with the same key, or even <em>sortByKey()</em>.</p>
<p></p><pre class="crayon-plain-tag">scala> val pets = sc.parallelize(List(("cat", 1), ("dog", 1), ("cat", 2)))
pets: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[8] at parallelize at <console>:12

scala> pets.collect()
res12: Array[(String, Int)] = Array((cat,1), (dog,1), (cat,2))

scala> pets.reduceByKey((a, b) => a + b).collect()
res9: Array[(String, Int)] = Array((dog,1), (cat,3))

scala> pets.groupByKey().collect()
res10: Array[(String, Iterable[Int])] = Array((dog,CompactBuffer(1)), (cat,CompactBuffer(1, 2)))

scala> pets.sortByKey().collect()
res11: Array[(String, Int)] = Array((cat,1), (cat,2), (dog,1))

scala></pre><p></p>
<p>Now let&#8217;s use the Shell to see how easily you can implement the MapReduce WordCount example in a single line:</p>
<p></p><pre class="crayon-plain-tag">scala> val counts = lines.flatMap(line => line.split(" ")).map(word => (word, 1)).reduceByKey((x, y) => x + y)
counts: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[18] at reduceByKey at <console>:14

scala> counts.collect()
res16: Array[(String, Int)] = Array((package,1), (this,1), (Because,1), (Python,2), (cluster.,1), (its,1), ([run,1), (general,2), (YARN,,1), (have,1), (pre-built,1), (locally.,1), (changed,1), (locally,2), (sc.parallelize(1,1), (only,1), (several,1), (This,2), (basic,1), (first,1), (documentation,3), (Configuration,1), (learning,,1), (graph,1), (Hive,2), (["Specifying,1), ("yarn-client",1), (page](http://spark.apache.org/documentation.html),1), ([params]`.,1), (application,1), ([project,2), (prefer,1), (SparkPi,2), (<http://spark.apache.org/>,1), (engine,1), (version,1), (file,1), (documentation,,1), (MASTER,1), (example,3), (are,1), (systems.,1), (params,1), (scala>,1), (provides,1), (refer,2), (configure,1), (Interactive,2), (distribution.,1), (can,6), (build,3), (when,1), (Apache,1),...
scala></pre><p></p>
<h1>Spark Applications</h1>
<p>For writing a Spark Application it&#8217;s possible to use Scala, Python or Java. What I&#8217;m going to do is to use Java 8 to take advantage of the new features of the language in order to have a less verbose syntax.</p>
<h2>Word count Java application</h2>
<p>First, use the appropriate dependency. For instance, with maven:</p>
<p></p><pre class="crayon-plain-tag">&lt;dependency&gt;
			&lt;groupId&gt;org.apache.spark&lt;/groupId&gt;
			&lt;artifactId&gt;spark-core_2.10&lt;/artifactId&gt;
			&lt;version&gt;1.2.1&lt;/version&gt;
		&lt;/dependency&gt;</pre><p></p>
<p>Then, you have to instantiate your own <strong>SparkContext</strong>, and it&#8217;s done via a <strong>SparkConf</strong> object. We use the minimal configuration: a name for the cluster URL (&#8220;local&#8221; to use a local cluster) and an application name to identify the application on the cluster:</p>
<p></p><pre class="crayon-plain-tag">SparkConf conf = new SparkConf().setMaster(&quot;local&quot;).setAppName(&quot;Word Count with Spark&quot;);
		JavaSparkContext sc = new JavaSparkContext(conf);</pre><p></p>
<p>Now, before writing Java, code it&#8217;s necessary to explain the differences with Scala.</p>
<p>Spark is written in Scala and it takes full advantage of its features. But Java lacks of some of them. So Spark provides alternatives with interfaces or concrete classes.</p>
<p>Let&#8217;s see the Word Count example in Spark written in Scala:</p>
<p></p><pre class="crayon-plain-tag">val file = spark.textFile(&quot;file&quot;)
val counts = file.flatMap(line =&gt; line.split(&quot; &quot;))
                 .map(word =&gt; (word, 1))
                 .reduceByKey(_ + _)
counts.saveAsTextFile(&quot;out&quot;)</pre><p></p>
<p>Java didn&#8217;t accept functions as parameters, so Spark provides interfaces in the <em>org.apache.spark.api.java.function</em> package to be implemented, either as anonymous inner classes or as named classes, to be passed as arguments of the functions (<em>flatMap()</em>, <em>map()</em>, <em>reduceByKey()</em>, &#8230;)</p>
<p>In our case, these are the functions that are needed:</p>
<ul>
<li><strong>FlatMapFunction<T, R></strong> with the method <em>Iterable<R> call(T t)</em> to return zero or more output records from each input record (t).</li>
<li><strong>PairFunction<T, K, V></strong> with the method <em>Tuple2<K, V> call(T t)</em> to return key-value pairs (Tuple2<K, V>), and can be used to construct PairRDDs.</li>
<li><strong>Function2<T1, T2, R></strong> with the method <em>R call(T1 v1, T2 v2)</em>, a two-argument function that takes arguments of type T1 and T2 and returns an R.</li>
</ul>
<p>Java doesn&#8217;t have a native implementation of Tuple (as <a href="https://twitter.com/lukaseder" title="Lukas Eder twitter account" target="_blank">Lukas Eder</a> said <em>On a side-note</em> at <a href="http://blog.jooq.org/2015/01/23/how-to-translate-sql-group-by-and-aggregations-to-java-8/" title="How to Translate SQL GROUP BY and Aggregations to Java 8" target="_blank">here</a> &#8220;Why the JDK doesn’t ship with built-in tuples like C#’s or Scala’s escapes me.&#8221;, in other words, <strong><em>&#8220;Functional programming without tuples is like coffee without sugar: A bitter punch in your face.&#8221;</em></strong>)</p>
<p>For that reason, Spark provides several implementations for Tuple in the <em>scala</em> package.</p>
<p>But, Java has evolved, and now functions are first class citizens, so it’s possible to pass them as parameters for other functions, thus it’s very easy to write the Java 8 version of the word count in Spark using lambdas (since the provided interfaces have a sole public method. And the result is almost as clear as the Scala version)</p>
<p></p><pre class="crayon-plain-tag">JavaRDD&lt;String&gt; lines = sc.textFile(&quot;file&quot;);
		JavaPairRDD&lt;String, Integer&gt; counts = lines.flatMap(line -&gt; Arrays.asList(line.split(&quot; &quot;)))
			.mapToPair(word -&gt; new Tuple2&lt;String, Integer&gt;(word, 1))
			.reduceByKey((x, y) -&gt; x + y);
		counts.saveAsTextFile(&quot;out&quot;);</pre><p></p>
<p>The complete source code is <a href="https://github.com/jbbarquero/spark-examples" title="spark-examples" target="_blank">available at GitHub</a>.</p>
<h2>Build and run</h2>
<p>Now, we only have to build the project (with maven) and submit it to Spark (with <strong>bin/spark-submit</strong>). From the root directory of the application (note: the out directory must not exists, so remove it previously if you need so with <strong><em>rm -r out</em></strong>):</p>
<p></p><pre class="crayon-plain-tag">$ mvn clean install
$ ~/Applications/spark-1.2.1-bin-hadoop2.4/bin/spark-submit --class com.malsolo.spark.examples.WordCount target/spark-examples-0.0.1-SNAPSHOT.jar</pre><p></p>
<p>Finally, we can see the results to compare with the ones obtained <a href="http://malsolo.com/blog4java/?p=516" title=" Getting started with Hadoop" target="_blank">using Hadoop</a>:</p>
<p></p><pre class="crayon-plain-tag">$ cat out/part-00000 | grep President
(President,,26)
(President,72)
(President.,8)
(Vice-President,5)
(Vice-President,,5)
(Vice-President;,1)
(President;,3)
(Vice-President.,1)

$ cat out/part-00000 | grep United
(United,85)

$ cat out/part-00000 | grep State
(State,47)
(States,46)
(States.",1)
(State.,6)
(States,,55)
(State,,20)
(States:,2)
(States.,8)
(Statement,1)
(States;,13)
(State;,4)</pre><p></p>
<h1>Shared Variables</h1>
<p>Spark closures and the variables they use are sent separately to the tasks running on the cluster, thus the variables created in the driver program are recieved in the tasks as a new copy, so updates on these copies are not propagated back to the driver.</p>
<p>Spark has two kinds of shared variables, <strong>accumulators</strong> and <strong>broadcast variables</strong>, to solve that problem as well as for solving issues related with the amount of data that is sent across the cluster.</p>
<h2>Accumulators</h2>
<p>Variables that can be used to aggregate values from worker nodes back to the driver program. In a nutshell:</p>
<ul>
<li>They are created with <em>SparkContext.accumulator(initialValue)</em> that returns an <em>org.apache.spark.Accumulator[T]</em> (with T, the type of initialValue)</li>
<li>Worker code adds values with <em>+=</em> in Scala or the function <em>add()</em> in Java.</li>
<li>The driver program can access with <em>value</em> in Scala or <em>value()</em>/<em>setValue()</em> in Java (accessing from worker code throws an exception)</li>
<li>The right value will be obtained after calling an <em><strong>action</strong></em> (remember that <u><em><strong>transformations</strong></em> are lazy operations</u>)</li>
</ul>
<p>Spark has built-in support for accumulators of type Integer, but you can create custom Accumulators by extending <a href="http://spark.apache.org/docs/1.2.1/api/java/index.html?org/apache/spark/AccumulatorParam.html" title="AccumulatorParam API" target="_blank">AccumulatorParam</a>.</p>
<p>Let&#8217;s see an example that counts the empty lines in the file that we use to count words:</p>
<p></p><pre class="crayon-plain-tag">public static void main(String[] args) {
		SparkConf conf = new SparkConf().setMaster(&quot;local&quot;).setAppName(&quot;Word Count with Spark&quot;);
		JavaSparkContext sc = new JavaSparkContext(conf);
		
		JavaRDD&lt;String&gt; lines = sc.textFile(INPUT_FILE_TEXT);
		
		final Accumulator&lt;Integer&gt; blankLines = sc.accumulator(0);
		
		@SuppressWarnings(&quot;resource&quot;)
		JavaPairRDD&lt;String, Integer&gt; counts = lines.flatMap(line -&gt; 
			{
				if (&quot;&quot;.equals(line)) {
					blankLines.add(1);
				}
				return Arrays.asList(line.split(&quot; &quot;));
			})
			.mapToPair(word -&gt; new Tuple2&lt;String, Integer&gt;(word, 1))
			.reduceByKey((x, y) -&gt; x + y);

		counts.saveAsTextFile(OUTPUT_FILE_TEXT);
		
		System.out.println(&quot;Blank lines: &quot; + blankLines.value());
		
		sc.close();
	}</pre><p></p>
<ul>
<li>In line 5 we create an Accumulator<Integer> initialized to 0</li>
<li>In lines 11 to 16 we modify the FlatMapFunction to add 1 if the input line is empty</li>
<li>In line 22 we print the value of the content. After the <em>saveAsTextFile()</em> action.</li>
</ul>
<p>Let&#8217;s try:</p>
<p></p><pre class="crayon-plain-tag">$ rm -r out
$ mvn clean install
$ ~/Applications/spark-1.2.1-bin-hadoop2.4/bin/spark-submit --class com.malsolo.spark.examples.WordCount target/spark-examples-0.0.1-SNAPSHOT.jar

Spark assembly has been built with Hive, including Datanucleus jars on classpath
15/03/02 15:26:22 WARN Utils: Your hostname, xxx resolves to a loopback address: 127.0.1.1; using yyy.yyy.y.yy instead (on interface eth0)
15/03/02 15:26:22 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address
15/03/02 15:26:23 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Blank lines: 169
$</pre><p></p>
<h2>Broadcast variables</h2>
<p>Shared variable to efficiently distribute large read-only values to all the worker nodes.</p>
<p>If you need to use the same same variable in multiple parallel operations, it&#8217;s likely you’d rather share it instead of letting Spark sends it separately for each operation.</p>
<p>In a nutshell:</p>
<ul>
<li>They are created with SparkContext.broadcast(initValue) on an object of type T that has to be Serializable.</li>
<li>Access its value with <em>value</em> in Scala or <em>value()</em> in Java.</li>
<li>The value shouldn&#8217;t be modified after creation, because the change will only happen in one node.</li>
</ul>
<p>Let’s see an example with a list of words that have not to be included in the count (a short list, but enough to see the concept):</p>
<p></p><pre class="crayon-plain-tag">public static void main(String[] args) {
		SparkConf conf = new SparkConf().setMaster(&quot;local&quot;).setAppName(&quot;Word Count with Spark&quot;);
		JavaSparkContext sc = new JavaSparkContext(conf);
		
		JavaRDD&lt;String&gt; lines = sc.textFile(INPUT_FILE_TEXT);
		
		final Accumulator&lt;Integer&gt; blankLines = sc.accumulator(0);
		
		final Broadcast&lt;List&lt;String&gt;&gt; wordsToIgnore = sc.broadcast(getWordsToIgnore());
		
		@SuppressWarnings(&quot;resource&quot;)
		JavaPairRDD&lt;String, Integer&gt; counts = lines.flatMap(line -&gt; 
			{
				if (&quot;&quot;.equals(line)) {
					blankLines.add(1);
				}
				return Arrays.asList(line.split(&quot; &quot;));
			})
			.filter(word -&gt; !wordsToIgnore.value().contains(word))
			.mapToPair(word -&gt; new Tuple2&lt;String, Integer&gt;(word, 1))
			.reduceByKey((x, y) -&gt; x + y);
		
		counts.saveAsTextFile(OUTPUT_FILE_TEXT);
		
		System.out.println(&quot;Blank lines: &quot; + blankLines.value());
		
		sc.close();
	}

	private static List&lt;String&gt; getWordsToIgnore() {
		return Arrays.asList(&quot;the&quot;, &quot;of&quot;, &quot;and&quot;, &quot;for&quot;);
	}</pre><p></p>
<ul>
<li>In line 9 we create the broadcast variable: a list of words to ignore. In lines 30 to 31 we only return 4 words, but it&#8217;s easy to see that the list could be big enough.</li>
<li>In line 19 we access the broadcast variable with the <em>value()</em> method and use it in a filter method.</li>
</ul>
<h1>Resources</h1>
<ul>
<li>Source code at <a href="https://github.com/jbbarquero/spark-examples" title="spark-examples" target="_blank">GitHub</a></li>
<li><a title="Learning Spark" href="http://shop.oreilly.com/product/0636920028512.do" target="_blank">Learning Spark</a>. By Holden Karau, Andy Konwinski, Patrick Wendell, Matei Zaharia (O&#8217;Reilly Media)</li>
<li><a title="Cloudera Developer Training for Apache Spark" href="http://cloudera.com/content/cloudera/en/training/courses/spark-training.html" target="_blank">Cloudera Developer Training for Apache Spark</a>. By Diana Carroll (Cloudera training)</li>
<li><a title="Parallel Programming with Spark" href="https://www.youtube.com/watch?v=7k4yDKBYOcw" target="_blank">Parallel Programming with Spark (Part 1 &amp; 2)</a>. By Matei Zaharia ((UC Berkeley AMPLab YouTube channel))</li>
<li><a title="Advanced Spark Features" href="https://www.youtube.com/watch?v=w0Tisli7zn4" target="_blank">Advanced Spark Features</a>. By Matei Zaharia (UC Berkeley AMPLab YouTube channel)</li>
<li><a title="A Deeper Understanding of Spark Internals" href="https://www.youtube.com/watch?v=dmL0N3qfSc8" target="_blank">A Deeper Understanding of Spark Internals</a>. By Aaron Davidson (Apache Spark YouTube channel)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://malsolo.com/blog4java/?feed=rss2&#038;p=679</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting started with Hadoop</title>
		<link>http://malsolo.com/blog4java/?p=516</link>
		<comments>http://malsolo.com/blog4java/?p=516#comments</comments>
		<pubDate>Wed, 25 Feb 2015 15:36:14 +0000</pubDate>
		<dc:creator><![CDATA[Javier (@jbbarquero)]]></dc:creator>
				<category><![CDATA[Big Data]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Hadoop]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://malsolo.com/blog4java/?p=516</guid>
		<description><![CDATA[Hadoop Introduction Hadoop is an open source framework for distributed fault-tolerant data storage and batch processing. It allows you to write applications for processing really huge data sets across clusters of computers using simple programming model with linear scalability on &#8230; <a href="http://malsolo.com/blog4java/?p=516">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<h1>Hadoop Introduction</h1>
<p>Hadoop is an open source framework for distributed fault-tolerant data storage and batch processing. It allows you to write applications for processing really huge data sets across clusters of computers using simple programming model with linear scalability on commodity hardware. Commodity hardware means cheaper hardware than the dedicated servers that are sold by many vendors. Linear scalability means that you have only to add more machines (nodes) to the Hadoop cluster.</p>
<p>The key concept for Hadoop is <strong><em>move-code-to-data</em></strong>, that is, data is distributed across the nodes of the Hadoop cluster and the applications (the jar files) are later sent to that nodes instead of vice versa (as in Java EE where applications are centralized in a application server and the data is collected to it over the network) in order to process the data locally. </p>
<p>At its core, Hadoop has two parts:</font></p>
<p>· <strong>Hadoop Distributed File System</strong> (<strong>HDFS™</strong>): a distributed file system that provides high-throughput access to application data.<br />
· <strong>YARN</strong> (<strong>Yet Another Resource Negotiator</strong>): a framework for job scheduling and cluster resource management.</p>
<p>As you can see in the very definition of the Apache Hadoop website (<a href="http://hadoop.apache.org/#What+Is+Apache+Hadoop%3Fhttp://" title="What is Apache Hadoop?" target="_blank">what is Apache Hadoop?</a>), Hadoop offers as a third component <strong>Hadoop MapReduce</strong>, a batch-based, distributed computing framework modeled after Google’s paper on MapReduce. It allows you to parallelize work over a large amount of raw data by splitting the input dataset into independent chunks which are processed by the map tasks (initial ingestion and transformation) in parallel, whose outputs are sorted and then passed to the reduce tasks (aggregation or summarization).</p>
<p>In the previous version of Hadoop (Hadoop 1), the implementation of MapReduce was based on a master <em>JobTracker</em>, for  resource management and job scheduling/monitoring, and per-node slaves called <em>TaskTracker</em> to launch/teardown tasks. But it had scalability problems, specially when you wanted very large clusters (more than 4,000 nodes).</p>
<p>So, MapReduce has undergone a complete overhaul and now is called MapReduce 2.0 (MRv2), but it is not a part by itself, currently, <u><strong>MapReduce</strong> is a YARN-based system</u>. That&#8217;s the reason why we can say that Hadoop has two main parts: HDFS and YARN.</p>
<h1>Hadoop ecosystem</h1>
<p>Besides the two core technologies, the distributed file system (HDFS) and Map Reduce (MR), there are a lot of projects that expand Hadoop with additional useful technologies, in such a way that we can consider all of them an ecosystem around Hadoop.</p>
<p>Next, a list of some of these projects, organized by some kind of categories:</p>
<ul>
<li><strong>Data Ingestion:</strong> to move data from and into HDFS
<ul>
<li><u>Flume</u>: a system for moving data into HDFS from remote systems using configurable memory-resident daemons that watch for data on those systems and then forward the data to Hadoop. For example, weblogs from multiple servers to HDFS.</li>
<li><u>Sqoop</u>: a tool for efficient bulk transfer of data between structured data stores (such as relational databases) and HDFS.</li>
</ul>
</li>
<li><strong>Data Processing:</strong>
<ul>
<li><u>Pig</u>: a procedural language for querying and data transform with scripts in a data flow language call PigLatin.</li>
<li><u>Hive</u>: a declarative SQL-like kanguage.</li>
<li><u>Spark</u>: an in-memory distributed data processing that breaks problems up over all of the Hadoop nodes, but keeps the data in memory for better performance and can be rebuilt with the details stored in the Resilient Distributed Dataset (RDD) from an external store (usually HDFS).</li>
<li><u>Storm</u>: a distributed real-time computation system for processing fast, large streams of data.</li>
</ul>
</li>
<li><strong>Data Formats:</strong>
<ul>
<li><u>Avro</u>: a language-neutral data serialization system. Expressed as JSON.</li>
<li><u>Parquet</u>: a compressed columnar storage format that can efficiently store nested data</li>
</ul>
</li>
<li><strong>Storage:</strong>
<ul>
<li><u>HBase</u>: a scalable, distributed database that supports structured data storage for large tables.</li>
<li><u>Accumulo</u>: a scalable, distributed database that supports structured data storage for large tables.</li>
</ul>
</li>
<li><strong>Coordination:</strong>
<ul>
<li><u>Zookeeper</u>: a high-performance coordination service for distributed applications.</li>
</ul>
</li>
<li><strong>Machine Learning:</strong>
<ul>
<li><u>Mahout</u>: a scalable machine learning and data mining library: classification, clustering, pattern mining, collaborative filtering and so on.</li>
</ul>
</li>
<li><strong>Workflow Management:</strong>
<ul>
<li><u>Oozie</u>: a service for running and scheduling workflows of Hadoop jobs (including Map-Reduce, Pig, Hive, and Sqoop jobs).</li>
</ul>
</li>
</ul>
<h1>Hadoop installation</h1>
<p>To install Hadoop on a single machine to try it out, just download the compressed file for the desired version and unpack it on the filesystem.</p>
<h2>Prerequisites</h2>
<p>There is some required software for running Apache Hadoop:</p>
<ul>
<li>Java. It&#8217;s also necessary to inform Hadoop where Java is via the environment variable JAVA_HOME</li>
<p></p><pre class="crayon-plain-tag">$ java -version
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
$ echo $JAVA_HOME
/usr/lib/jvm/java-8-oracle</pre><p></p>
<li>ssh: I have Ubuntu 14.04 that comes with ssh, but I had to manually install a server.</li>
<p></p><pre class="crayon-plain-tag">$ which ssh
/usr/bin/ssh
$ which sshd
/usr/sbin/sshd</pre><p></p>
<li>On Mac OSX, make sure <strong>Remote Login</strong> (under <strong>System Preferences</strong> -> <strong>File Sharing</strong>) is enabled for the current user or for all users.</li>
<li>On Windows, the best option is to follow the instructions at the Wiki: <a href="http://wiki.apache.org/hadoop/Hadoop2OnWindows" title="Build and Install Hadoop 2.x or newer on Windows" target="_blank">Build and Install Hadoop 2.x or newer on Windows</a>.</li>
</ul>
<h2>Download and install</h2>
<p>To get a Hadoop distribution, download a recent stable release from one of the <a href="http://www.apache.org/dyn/closer.cgi/hadoop/common/http://" title="Apache Download Mirrors" target="_blank">Apache Download Mirrors</a>.</p>
<p>There are several directories, for the current, last stable, last v1 stable version and so on. Basically, you&#8217;ll download a tar gzipped file named <strong>hadoop-x.y.z.tar.gz</strong>, for instance: hadoop-2.6.0.tar.gz.</p>
<p>You can unpack it wherever you want and then point the PATH to that directory. For example:</p>
<p></p><pre class="crayon-plain-tag">$ tar xzf hadoop-2.6.0.tar.gz
$
$ export HADOOP_HOME=~/Applications/hadoop-2.6.0
$ export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin</pre><p></p>
<p>Now you can verify the installation by typing <strong>hadoop version</strong>:</p>
<p></p><pre class="crayon-plain-tag">$ hadoop version
Hadoop 2.6.0
Subversion https://git-wip-us.apache.org/repos/asf/hadoop.git -r e3496499ecb8d220fba99dc5ed4c99c8f9e33bb1
Compiled by jenkins on 2014-11-13T21:10Z
Compiled with protoc 2.5.0
From source with checksum 18e43357c8f927c0695f1e9522859d6a
This command was run using ~/Applications/hadoop-2.6.0/share/hadoop/common/hadoop-common-2.6.0.jar
$</pre><p></p>
<h2>Configuration</h2>
<p>Hadoop has three supported modes:</p>
<ul>
<li>Local (Standalone) Mode: a single Java process with daemons running. For development testing and debugging.</li>
<li>Pseudo-Distributed Mode: each Hadoop daemon runs in a separate Java process. For simulating a cluster on a small scale.</li>
<li>Fully-Distributed Mode: the Hadoop daemons run on a cluster of machines. If you want to take a look, see the oficial documentation: <a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/ClusterSetup.html" title="Hadoop Cluster Setup" target="_blank">Hadoop MapReduce Next Generation &#8211; Cluster Setup</a>.</li>
</ul>
<p>In standalone mode, there is no further action to take, the default properties are enough and there are no daemons to run.</p>
<p>In pseudodistributed mode, you have to set up your computer as described at <a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/SingleCluster.htmlhttp://" title="Hadoop MapReduce Next Generation - Setting up a Single Node Cluster." target="_blank">Hadoop MapReduce Next Generation &#8211; Setting up a Single Node Cluster</a>. But let&#8217;s review the steps needed.</p>
<p>You need at least a minimum configuration with four files in <strong>HADOOP_HOME/etc/hadoop/</strong>:</p>
<ul>
<li><strong>core-site.xml</strong>. Common configuration, default values at <a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/core-default.xml" title="core-default.xml" target="_blank">Configuration: core-default.xml</a></li>
<p></p><pre class="crayon-plain-tag">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;?xml-stylesheet type=&quot;text/xsl&quot; href=&quot;configuration.xsl&quot;?&gt;
&lt;configuration&gt;
	&lt;property&gt;
		&lt;name&gt;fs.defaultFS&lt;/name&gt;
		&lt;value&gt;hdfs://localhost:8020&lt;/value&gt;
	&lt;/property&gt;
&lt;/configuration&gt;</pre><p></p>
<p><em>fs.defaultFS</em> replaces the deprecated <em>fs.default.name</em> whose default value is <em>file://</em></p>
<li><strong>hdfs-site.xml</strong>. HDFS configuration, default values at <a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml" title="hdfs-default.xml" target="_blank">Configuration: hdfs-default.xml</a></li>
<p></p><pre class="crayon-plain-tag">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;?xml-stylesheet type=&quot;text/xsl&quot; href=&quot;configuration.xsl&quot;?&gt;
&lt;configuration&gt;
	&lt;property&gt;
		&lt;name&gt;dfs.replication&lt;/name&gt;
		&lt;value&gt;1&lt;/value&gt;
	&lt;/property&gt;
&lt;/configuration&gt;</pre><p></p>
<p><em>dfs.replication</em>is the default block replication, unless other is specified at creation time. The default value is 3, but we use 1 because we have only one node.</p>
<p>Other useful values are:</p>
<p><em>dfs.namenode.name.dir</em>, local path for storing the fsimage by the NN (defaults to file://${hadoop.tmp.dir}/dfs/name with hadoop.tmp.dir configurable at core-site.xml with default value /tmp/hadoop-${user.name})</p>
<p><em>dfs.datanode.data.dir</em>, local path for storing blocks by the DN (defaults to file://${hadoop.tmp.dir}/dfs/data)</p>
<li><strong>mapred-site.xml</strong>. MapReduce configuration, default values at <a href="http://hadoop.apache.org/docs/current/hadoop-mapreduce-client/hadoop-mapreduce-client-core/mapred-default.xml" title="mapred-default.xml" target="_blank">Configuration: mapred-default.xml</a></li>
<p></p><pre class="crayon-plain-tag">&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;?xml-stylesheet type=&quot;text/xsl&quot; href=&quot;configuration.xsl&quot;?&gt;
&lt;configuration&gt;
	&lt;property&gt;
		&lt;name&gt;mapreduce.framework.name&lt;/name&gt;
		&lt;value&gt;yarn&lt;/value&gt;
	&lt;/property&gt;
&lt;/configuration&gt;</pre><p></p>
<p><em>mapreduce.framework.name</em>, the runtime framework for executing MapReduce jobs: local, classic or yarn.</p>
<p>Other useful values are:</p>
<p><em>mapreduce.jobtracker.system.dir</em>, the directory where MapReduce stores control files (defaults to ${hadoop.tmp.dir}/mapred/system).</p>
<p><em>mapreduce.cluster.local.dir</em>, the local directory where MapReduce stores intermediate data files (defaults to ${hadoop.tmp.dir}/mapred/local)</p>
<li><strong>yarn-site.xml</strong>. YARN configuration, default values at <a href="http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-common/yarn-default.xml" title="yarn-default.xml" target="_blank">Configuration: yarn-default.xml</a></li>
</ul>
<p></p><pre class="crayon-plain-tag">&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;configuration&gt;
	&lt;property&gt;
		&lt;name&gt;yarn.resourcemanager.hostname&lt;/name&gt;
		&lt;value&gt;localhost&lt;/value&gt;
	&lt;/property&gt;
	&lt;property&gt;
		&lt;name&gt;yarn.nodemanager.aux-services&lt;/name&gt;
		&lt;value&gt;mapreduce_shuffle&lt;/value&gt;
	&lt;/property&gt;
&lt;/configuration&gt;</pre><p></p>
<p><em>yarn.resourcemanager.hostname</em>, the host name of the Resource Manager.</p>
<p><em>yarn.nodemanager.aux-services</em>, list of auxiliary services executed by the Node Manager. The value mapreduce_shuffle is for the Suffle/Sort in MapReduce that is an auxilary service in Hadoop 2.x. </p>
<h2>Configuring SSH</h2>
<p>Pseudodistributed mode is like fully distributed mode with a single host: localhost. In order to start the daemons on the set of hosts in the cluster, SSH is used. So we&#8217;ll configure SSH to log in without password.</p>
<p>Remember that you need to have SSH installed and a server running. On Ubuntu, try this if you need so:</p>
<p></p><pre class="crayon-plain-tag">$ sudo apt-get install ssh</pre><p></p>
<p>Now create a SSH key with an empty passprhase</p>
<p></p><pre class="crayon-plain-tag">$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa_hadoop
$ cat ~/.ssh/id_rsa_hadoop.pub >> ~/.ssh/authorized_keys</pre><p></p>
<p>Finally, test if you can connect without a pasword by trying:</p>
<p></p><pre class="crayon-plain-tag">$ ssh localhost</pre><p></p>
<h2>First steps with HDFS</h2>
<p>Before using HDFS for the first time, some steps must be performed:</p>
<h3>Formatting the HDFS filesystem</h3>
<p>Just run the following command:</p>
<p></p><pre class="crayon-plain-tag">$ hdfs namenode -format</pre><p></p>
<h3>Starting the daemons</h3>
<p>To start the HDFS, YARN, and MapReduce daemons, type:</p>
<p></p><pre class="crayon-plain-tag">$ start-dfs.sh
$ start-yarn.sh
$ mr-jobhistory-daemon.sh start historyserver</pre><p></p>
<p>You can check what processes are running with the Java&#8217;s <strong>jps</strong> command:</p>
<p></p><pre class="crayon-plain-tag">$ jps
25648 NodeManager
25521 ResourceManager
25988 JobHistoryServer
25355 SecondaryNameNode
25180 DataNode
26025 Jps
$</pre><p></p>
<h3>Stopping the daemons</h3>
<p>Once it&#8217;s over, you can stop the daemons with:</p>
<p></p><pre class="crayon-plain-tag">$ mr-jobhistory-daemon.sh stop historyserver
$ stop-yarn.sh
$ stop-dfs.sh</pre><p></p>
<h3>Creating A User Directory</h3>
<p>You can create a home directory for a user with the next command:</p>
<p></p><pre class="crayon-plain-tag">$ hadoop fs -mkdir -p ~/Documents/hadoop-home/</pre><p></p>
<h1>Other Hadoop installations</h1>
<p>There are another way to get installed Hadoop, that is, using companies that provide products that include Apache Hadoop or some kind of derivatives:</p>
<ul>
<li><a href="http://aws.amazon.com/elasticmapreduce/" title="Amazon EMR" target="_blank">Amazon Elastic MapReduce (Amazon EMR)</a></li>
<li><a href="http://www.cloudera.com/content/cloudera/en/downloads.html" title="CDH" target="_blank">Cloudera&#8217;s Distribution including Apache Hadoop (CDH)</a></li>
<li><a href="http://hortonworks.com/hdp/" title="HDP" target="_blank">Hortonworks Data Platform Powered by Apache Hadoop (HDP)</a></li>
<li><a href="https://www.mapr.com/" title="MapR" target="_blank">MapR Technologies</a></li>
<li><a href="http://pivotal.io/big-data/pivotal-hd" title="Pivotal HD" target="_blank">Pivotal HD</a></li>
</ul>
<h1>Hadoop Distributed File System (HDFS)</h1>
<p>The HDFS filesystem designed for distributed storage of very large files (hundreds of megabytes, gigabytes, or terabytes in size) and distributed processing using commodity hardware. It is a hierarchical UNIX-like file system, but internally it splits large files into blocks (with size from 32MB to 128MB, being 64MB the default), in order to perform a distribution and a replication of these blocks among the nodes of the Hadoop cluster.The applications that use HDFS usually write data once and read data many times.</p>
<p>The HDFS has two types of nodes:</p>
<ul>
<li>The master <strong>NameNode</strong> (NN), that stores the filesystem tree and the metadata for locating the files and directories in the tree that are actually located in the DataNodes. It stores this information in memory, however, to ensure against data loss, it&#8217;s also saved to disk using two files: the namespace image and the edit log.
<ul>
<li>fsimage: a point in time snapshot of what HDFS looks like.</li>
<li>edit log: the deltas or changes to HDFS since the last snapshot.</li>
</ul>
<p>Both are prediodically merged.</p>
</li>
<li>The <strong>DataNode</strong>s (DN), that are responsible for serving the actual file data (once the client knows which one to use after contacting the NameNode). They also sends heatbeats every 3 seconds (by default) to the NN and block reports every 1 hour (by default) to the DN both for maintenance purposes.</li>
</ul>
<p>There is also a node poorly named <strong>Secondary NameNode</strong> that is not a failover node nor a backup node, it periodically merges the namespace image with the edit log to prevent the edit log from becoming too large. Thus, the best name for it is <strong>Checkpoint Node</strong>.</p>
<h2>The Command-Line Interface</h2>
<p>Once you have installed Hadoop, you can interact with HDFS, as well as other file systems that Hadoop supports (local filesystem, HFTP FS, S3 FS, and others), using the command line. The FS shell is invoked by:</p>
<p></p><pre class="crayon-plain-tag">$ hadoop fs <args></pre><p></p>
<p>Provided to you have hadoop in the PATH as we saw above.</p>
<p>You can find a list of available commands at <a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/FileSystemShell.html" title="FS shell" target="_blank">File System Shell</a>.</p>
<p>You can perform operations like:</p>
<ul>
<li><a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/FileSystemShell.html#copyFromLocal" title="copyFromLocal" target="_blank">copyFromLocal</a> (putting files into HDFS)</li>
<li><a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/FileSystemShell.html#copyToLocal" title="copyToLocal" target="_blank">copyToLocal</a> (getting files form HDFS)</li>
<li><a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/FileSystemShell.html#mkdir" title="mkdir" target="_blank">mkdir</a> (creating directories in HDFS)</li>
<li><a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/FileSystemShell.html#ls" title="ls" target="_blank">ls</a> (list files in HDFS)</li>
</ul>
<h2>Data exchange with HDFS</h2>
<p>Hadoop is mainly written in Java, being the core class for HDFS the abstract class <a href="https://github.com/apache/hadoop/blob/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java" title="fs.FileSystem" target="_blank">org.apache.hadoop.fs.FileSystem</a>, that represents a filesystem in Hadoop. The several concrete subclasses provide implementations from local filesystem (<a href="https://github.com/apache/hadoop/blob/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/LocalFileSystem.java" title="fs.LocalFileSystem" target="_blank">fs.LocalFileSystem</a>) to HDFS (<a href="https://github.com/apache/hadoop/blob/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DistributedFileSystem.java" title="hdfs.DistributedFileSystem" target="_blank">hdfs.DistributedFileSystem</a>), or Amazon S3 (<a href="https://github.com/apache/hadoop/blob/trunk/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3native/NativeS3FileSystem.java" title="fs.s3native.NativeS3FileSystem" target="_blank">fs.s3native.NativeS3FileSystem</a>) and many more (read-only HTTP, FTP server, &#8230;)</p>
<h3>Reading data</h3>
<p>Reading data using the Java API involves to obtain the abstract <a href="https://github.com/apache/hadoop/blob/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java" title="fs.FileSystem" target="_blank">FileSystem</a> via one of the factory methods (<strong><em>get()</em></strong>), or the convenient method for retrieving the local filesystem (<strong><em>getLocal()</em></strong>):</p>
<p><strong>public static FileSystem get(Configuration conf) throws IOException<br />
public static FileSystem get(URI uri, Configuration conf) throws IOException<br />
public static FileSystem get(URI uri, Configuration conf, String user)<br />
throws IOException<br />
public static LocalFileSystem getLocal(Configuration conf) throws IOException</strong></p>
<p>And then obtain an input stream for a file (that can be later be closed):</p>
<p><strong>public FSDataInputStream open(Path f) throws IOException<br />
public abstract FSDataInputStream open(Path f, int bufferSize) throws IOException</strong></p>
<p>With these methods on hand, the flow of the data in HDFS will be the next:</p>
<div id="attachment_601" style="width: 650px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2014/11/HDFS_Client_Read_File.jpg"><img src="http://malsolo.com/blog4java/wp-content/uploads/2014/11/HDFS_Client_Read_File.jpg" alt="HDFS read" width="640" height="367" class="size-full wp-image-601" /></a><p class="wp-caption-text">Reading from HDFS</p></div>
<ol>
<li>The client calls the <strong>open()</strong> method to read a file. A <strong>DistributedFileSystem</strong> is returned.</li>
<li>The DistributedFileSystem asks the <strong>NameNode</strong> for the block locations. The NameNode returns an ordered list of the DataNodes that have a copy of the block (sorted by proximity to the client). The DistributedFileSystem returns a <strong>FSDataInputStream</strong> to the client for it to read data from</li>
<li>The client calls <strong>read()</strong> on the input stream</li>
<li>The FSDataInputStream reads data for the client from the DataNode until there is no more data in that node.</li>
<li>The FSDataInputStream will manage the closing and opening connection to DataNodes for serving data to the client in a transparently way. It also manages validation (checksum) and errors (by trying to read data from a replica)</li>
<li>When the client has finished reading, it calls <strong>close()</strong> on the FSDataInputStream</li>
</ol>
<h3>Writing data</h3>
<p>The Java API allows you to create files with create methods (that, by the way, also create any parent directories of the file that don&#8217;t already exist). The API also includes a <strong>Progressable</strong> interface to be notified of the process of the data being written to the datanodes. It&#8217;s also possible to append data to an existing file, but this functionality is optional (S3 doesn&#8217;t support it from the time being)</p>
<p><strong>public FSDataOutputStream create(Path f) throws IOException<br />
public FSDataOutputStream append(Path f) throws IOException</strong></p>
<p>The output stream will be used for writing the data. Furthermore, the FSDataOutputStream can inform of the current position in the file.</p>
<p>The flow of the data written to HDFS with these methods is the next:</p>
<div id="attachment_602" style="width: 650px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2014/11/HDFS_Client_Write_File.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2014/11/HDFS_Client_Write_File.png" alt="HDFS write" width="640" height="416" class="size-full wp-image-602" /></a><p class="wp-caption-text">Writing to HDFS</p></div>
<ol>
<li>The client creates the file by calling <strong>create()</strong> on <strong>DistributedFileSystem</strong>.</li>
<li>DistributedFileSystem makes an RPC call to the namenode to create a<br />
new file in the filesystem’s namespace, with no blocks associated with it. The NameNode checks file existence and permission, throwing IOException if theres is any problem, otherwise, it returns a FSDataOutputStream for writing data to.</li>
<li>The data written by the client is splitted into packets that are sent to a <em>data queue</em>.</li>
<li>The data queue is consumed by the Data Streamer which streams the packets to a pipeline of DataNodes (one per replication factor). Each DataNode stores the packet and send it to the next DataNode in the pipeline.</li>
<li>There is another queue, ack queue, that contains the packets that are waiting for acknowledged by all the datanodes in the pipeline. If a DataNode fails in a write operation, the pipeline will be re-arranged transparently for the client.</li>
<li>When the client has finished writing data, it calls <strong>close()</strong> on the stream.</li>
<li>The remaining packets are flushed and, after receiving all the acknowledgments, the NameNode is notified that the write to the file is completed.</li>
</ol>
<h1>Apache YARN (Yet Another Resource Negotiator)</h1>
<p>YARN is Hadoop’s cluster resource management system. It provides provides APIs for requesting and working with cluster resources to be used not by user code, but for higher level APIs, like MapReduce v2, Spark, Tez&#8230;</p>
<p>YARN separates resource management and job scheduling/monitoring into separate daemons. In Hadoop 1.x these two functions were performed by the JobScheduler, that implies a bottleneck for scaling the Hadoop nodes in the cluster.</p>
<h2>YARN Components</h2>
<p>There are five major component types in a YARN cluster:</p>
<ul>
<li><strong>Resource Manager (RM)</strong>: a global per-cluster daemon that is solely responsible for allocating and managing resources available within the cluster.</li>
<li><strong>Node Manager (NM)</strong>: a per-node daemon that is responsible for creating, monitoring, and killing containers.</li>
<li><strong>Application Master (AM)</strong>: This is a per-application daemon whose duty is the negotiation of resources from the ResourceManager and to work with the NodeManager(s) to execute and monitor the tasks.</li>
<li><strong>Container</strong>: This is an abstract representation of a resource set that is given to a particular application:  memory and cpu. It&#8217;s a computational unit (one node runs several containers, but a container cannot cross a node boundary). The AM is a specialized container that is used to bootstrap and manage the entire application&#8217;s life cycle.</li>
<li><strong>Application Client</strong>: it submits applications to the RM and it specifies the type of AM needed to execute the application (for instance, MapReduce).</li>
</ul>
<h2>Anatomy of a YARN Request</h2>
<p>These are the steps involved in the submission of a job to the YARN framework.</p>
<div id="attachment_649" style="width: 632px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2015/02/yarn_architecture.gif"><img src="http://malsolo.com/blog4java/wp-content/uploads/2015/02/yarn_architecture.gif" alt="Anatomy of a YARN Request" width="622" height="385" class="size-full wp-image-649" /></a><p class="wp-caption-text">YARN architecture</p></div>
<ol>
<li>The client submits a job to the RM asking to run an AM process (Job Submission in the picture above).</li>
<li>The RM looks for resources to acquire a container on a node to launch an instance of the AM.</li>
<li>The AM registers with the RM to enable the client to query the RM for details about the AM.</li>
<li>Now the AM is running, and it could run the computation returning the result to the client, or it could request more containers to the RM to run a distributed computation (Resource Request in the picture above)</li>
<li>The application code executing in the launched container (tasks) reports its status to the AM through an application-specific protocol (MapReduce status in the picture above, that it&#8217;s assuming that the YARN application being executed is MapReduce).</li>
<li>Once the application completes execution, the AM deregisters with the RM, and the containers used are released back to the system.</li>
</ol>
<p>This process applies for each client that submits jobs. In the picture above there are two clients (the red one and the blue one)</p>
<h1>Hadoop first program: WordCount MapReduce</h1>
<p>MapReduce is a paradigm for data processing that uses two key phases:</p>
<ol>
<li><strong>Map</strong>: it performs a transformation on input key-value pairs to generate intermediate key-value pairs.</li>
<li><strong>Reduce</strong>: it performs a summarize function on intermediate key-value groups to generate the final output of key-value pairs.</li>
<li>The groups that are the input of the Reduce phase are created by sorting the output of the Map phase in an operation called as <strong>Short/Shuffle</strong> (in YARN, is an auxiliary service)
</ol>
<h2>Writing the program</h2>
<p>For writing a MapReduce program in Java for running it in Hadoop you need to provide a Mapper class, a Reducer class, and a driver program to run a job.</p>
<p>Let&#8217;s begin with <u>the Mapper class</u>, it will separate each word with a count of 1:</p>
<p></p><pre class="crayon-plain-tag">public class WordCountMapper extends Mapper&lt;LongWritable, Text, Text, IntWritable&gt; {
	
	private final static IntWritable ONE = new IntWritable(1);
	private Text word = new Text();
	
	@Override
	protected void map(LongWritable key, Text value,
			Mapper&lt;LongWritable, Text, Text, IntWritable&gt;.Context context)
			throws IOException, InterruptedException {
		String line = value.toString();
		StringTokenizer tokenizer = new StringTokenizer(line);
		while (tokenizer.hasMoreTokens()) {
			word.set(tokenizer.nextToken());
			context.write(word, ONE);
		}
	}

}</pre><p></p>
<p>Highlights here are the parameters of the Mapper class, in this case:</p>
<ol>
<li>The input key, a long that will be ignored</li>
<li>The input value, a line of text</li>
<li>The output key, the word to be counted</li>
<li>The output value, the count for the word, always one, as we said before.</li>
</ol>
<p>As you can see, instead of using Java types, it&#8217;s better to use Hadoop basic types that are optimized for network serialization (available in the <em>org.apache.hadoop.io</em> package)</p>
<p>The basic approach is to override the <em>map()</em> method and make use of the key and value input parameters, as well as the instance of a Context to write the output to: the words with its count (one, for the moment being)</p>
<p>Let&#8217;s continue with <u>the Reducer class</u>.</p>
<p></p><pre class="crayon-plain-tag">public class WordCountReducer extends Reducer&lt;Text, IntWritable, Text, IntWritable&gt; {
	@Override
	protected void reduce(Text key, Iterable&lt;IntWritable&gt; values,
			Reducer&lt;Text, IntWritable, Text, IntWritable&gt;.Context context)
			throws IOException, InterruptedException {
		int sum = 0;
		for (IntWritable val : values) {
			sum += val.get();
		}
		context.write(key, new IntWritable(sum));
	}
	
}</pre><p></p>
<p>The intermediate result from the Mapper will be partitioned by MapReduce in such a way that the same reducer will receive all output records containing the same key. MapReduce will also sort all the map output keys and will call each reducer only once for each output key along with a list of all the output values for this key.</p>
<p>Thus, to write a Mapper class, you override the method reduce that has as parameters the only key, the list of values as an iterable and an instance of the Context to write the final result to.</p>
<p>In our case, the reducer will sum the count that each words carry (always one) and it will write the result to the context.</p>
<p>Finally, <u>the Driver class</u>, the class that runs the MapReduce job.</p>
<p></p><pre class="crayon-plain-tag">public class WordCountDriver {
	
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		String[] myArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
		if (myArgs.length != 2) {
			System.err.println(&quot;Usage: WordCountDriver &lt;input path&gt; &lt;output path&gt;&quot;);
			System.exit(-1);
		}
		Job job = Job.getInstance(conf, &quot;Classic WordCount&quot;);
		job.setJarByClass(WordCountDriver.class);
		
		FileInputFormat.addInputPath(job, new Path(myArgs[0]));
		FileOutputFormat.setOutputPath(job, new Path(myArgs[1]));
		
		job.setMapperClass(WordCountMapper.class);
		job.setReducerClass(WordCountReducer.class);
		
		//job.setMapOutputKeyClass(Text.class);
		//job.setMapOutputValueClass(IntWritable.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(IntWritable.class);
		
		System.exit(job.waitForCompletion(true) ? 0 : 1);
	}
}</pre><p></p>
<p>First, create a Hadoop Configuration (the default values are enough for this example) and use the <em>GenericOptionsParser</em> class to parse only the generic Hadoop arguments. </p>
<p>To configure, submit and control the execution of the job, as well as to monitor its progress, use a <em>Job</em> object. Take care of configuring it (via its <em>set()</em> methods) before submitting the job or an <em>IllegalStateException</em> will be thrown.</p>
<p>In a Hadoop cluster, the JAR package will be distributed around the cluster, to allow Hadoop to locate this JAR we pass a class in the Job ’s <em>setJarByClass()</em> method.</p>
<p>Next, we specify the input and output paths by calling the static <em>addInputPath()</em> (or <em>setInputPaths</em>) method on <em>FileInputFormat()</em> (with a file, directory or file pattern) and the static <em>setOutputPath()</em> method on <em>FileOutputFormat</em> (with a non-existing directory, in order to avoid data loss from another job) respectively.</p>
<p>Then, the job is configured with the Mapper class and the Reducer class.</p>
<p>There is no need for specifying the map output types because they are the same than the ones produced by the Reducer class, but we need to indicate the output types for the reduce function.</p>
<p>Finally, the <em>waitForCompletion()</em> method on Job submits the job and waits for it to finish. The argument is a flag for verbosity in the generated output. The return value indicates success (true) or failure (false). We use it for the the program’s exit code (0 or 1).</p>
<h2>Running the program</h2>
<p>The source code is available at <a href="https://github.com/jbbarquero/mapreduce" title="Mapreduce first program" target="_blank">github</a>. You can download it, go to the directory and just run the next commands:</p>
<p></p><pre class="crayon-plain-tag">$ mvn clean install
$ export HADOOP_CLASSPATH=target/mapreduce-0.0.1-SNAPSHOT.jar
$ hadoop com.malsolo.hadoop.mapreduce.WordCountDriver data/the_constitution_of_the_united_states.txt out</pre><p></p>
<p>You will see something like this:</p>
<p></p><pre class="crayon-plain-tag">15/02/25 15:30:47 INFO Configuration.deprecation: session.id is deprecated. Instead, use dfs.metrics.session-id
15/02/25 15:30:47 INFO jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=
15/02/25 15:30:47 INFO input.FileInputFormat: Total input paths to process : 1
15/02/25 15:30:47 INFO mapreduce.JobSubmitter: number of splits:1
15/02/25 15:30:47 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_local284822998_0001
15/02/25 15:30:47 INFO mapreduce.Job: The url to track the job: http://localhost:8080/
15/02/25 15:30:47 INFO mapreduce.Job: Running job: job_local284822998_0001
15/02/25 15:30:47 INFO mapred.LocalJobRunner: OutputCommitter set in config null
15/02/25 15:30:47 INFO mapred.LocalJobRunner: OutputCommitter is org.apache.hadoop.mapreduce.lib.output.FileOutputCommitter
15/02/25 15:30:48 INFO mapred.LocalJobRunner: Waiting for map tasks
15/02/25 15:30:48 INFO mapred.LocalJobRunner: Starting task: attempt_local284822998_0001_m_000000_0
15/02/25 15:30:48 INFO mapred.Task:  Using ResourceCalculatorProcessTree : [ ]
15/02/25 15:30:48 INFO mapred.MapTask: Processing split: file:.../mapreduce/data/the_constitution_of_the_united_states.txt:0+45119
15/02/25 15:30:48 INFO mapred.MapTask: (EQUATOR) 0 kvi 26214396(104857584)
15/02/25 15:30:48 INFO mapred.MapTask: mapreduce.task.io.sort.mb: 100
15/02/25 15:30:48 INFO mapred.MapTask: soft limit at 83886080
15/02/25 15:30:48 INFO mapred.MapTask: bufstart = 0; bufvoid = 104857600
15/02/25 15:30:48 INFO mapred.MapTask: kvstart = 26214396; length = 6553600
15/02/25 15:30:48 INFO mapred.MapTask: Map output collector class = org.apache.hadoop.mapred.MapTask$MapOutputBuffer
15/02/25 15:30:48 INFO mapred.LocalJobRunner: 
15/02/25 15:30:48 INFO mapred.MapTask: Starting flush of map output
15/02/25 15:30:48 INFO mapred.MapTask: Spilling map output
15/02/25 15:30:48 INFO mapred.MapTask: bufstart = 0; bufend = 75556; bufvoid = 104857600
15/02/25 15:30:48 INFO mapred.MapTask: kvstart = 26214396(104857584); kvend = 26183792(104735168); length = 30605/6553600
15/02/25 15:30:48 INFO mapred.MapTask: Finished spill 0
15/02/25 15:30:48 INFO mapred.Task: Task:attempt_local284822998_0001_m_000000_0 is done. And is in the process of committing
15/02/25 15:30:48 INFO mapred.LocalJobRunner: map
15/02/25 15:30:48 INFO mapred.Task: Task 'attempt_local284822998_0001_m_000000_0' done.
15/02/25 15:30:48 INFO mapred.LocalJobRunner: Finishing task: attempt_local284822998_0001_m_000000_0
15/02/25 15:30:48 INFO mapred.LocalJobRunner: map task executor complete.
15/02/25 15:30:48 INFO mapred.LocalJobRunner: Waiting for reduce tasks
15/02/25 15:30:48 INFO mapred.LocalJobRunner: Starting task: attempt_local284822998_0001_r_000000_0
15/02/25 15:30:48 INFO mapred.Task:  Using ResourceCalculatorProcessTree : [ ]
15/02/25 15:30:48 INFO mapred.ReduceTask: Using ShuffleConsumerPlugin: org.apache.hadoop.mapreduce.task.reduce.Shuffle@1bd34bf7
15/02/25 15:30:48 INFO reduce.MergeManagerImpl: MergerManager: memoryLimit=334338464, maxSingleShuffleLimit=83584616, mergeThreshold=220663392, ioSortFactor=10, memToMemMergeOutputsThreshold=10
15/02/25 15:30:48 INFO reduce.EventFetcher: attempt_local284822998_0001_r_000000_0 Thread started: EventFetcher for fetching Map Completion Events
15/02/25 15:30:48 INFO reduce.LocalFetcher: localfetcher#1 about to shuffle output of map attempt_local284822998_0001_m_000000_0 decomp: 90862 len: 90866 to MEMORY
15/02/25 15:30:48 INFO reduce.InMemoryMapOutput: Read 90862 bytes from map-output for attempt_local284822998_0001_m_000000_0
15/02/25 15:30:48 INFO reduce.MergeManagerImpl: closeInMemoryFile -> map-output of size: 90862, inMemoryMapOutputs.size() -> 1, commitMemory -> 0, usedMemory ->90862
15/02/25 15:30:48 INFO reduce.EventFetcher: EventFetcher is interrupted.. Returning
15/02/25 15:30:48 INFO mapred.LocalJobRunner: 1 / 1 copied.
15/02/25 15:30:48 INFO reduce.MergeManagerImpl: finalMerge called with 1 in-memory map-outputs and 0 on-disk map-outputs
15/02/25 15:30:48 INFO mapred.Merger: Merging 1 sorted segments
15/02/25 15:30:48 INFO mapred.Merger: Down to the last merge-pass, with 1 segments left of total size: 90857 bytes
15/02/25 15:30:48 INFO reduce.MergeManagerImpl: Merged 1 segments, 90862 bytes to disk to satisfy reduce memory limit
15/02/25 15:30:48 INFO reduce.MergeManagerImpl: Merging 1 files, 90866 bytes from disk
15/02/25 15:30:48 INFO reduce.MergeManagerImpl: Merging 0 segments, 0 bytes from memory into reduce
15/02/25 15:30:48 INFO mapred.Merger: Merging 1 sorted segments
15/02/25 15:30:48 INFO mapred.Merger: Down to the last merge-pass, with 1 segments left of total size: 90857 bytes
15/02/25 15:30:48 INFO mapred.LocalJobRunner: 1 / 1 copied.
15/02/25 15:30:48 INFO Configuration.deprecation: mapred.skip.on is deprecated. Instead, use mapreduce.job.skiprecords
15/02/25 15:30:48 INFO mapred.Task: Task:attempt_local284822998_0001_r_000000_0 is done. And is in the process of committing
15/02/25 15:30:48 INFO mapred.LocalJobRunner: 1 / 1 copied.
15/02/25 15:30:48 INFO mapred.Task: Task attempt_local284822998_0001_r_000000_0 is allowed to commit now
15/02/25 15:30:48 INFO output.FileOutputCommitter: Saved output of task 'attempt_local284822998_0001_r_000000_0' to file:.../out/_temporary/0/task_local284822998_0001_r_000000
15/02/25 15:30:48 INFO mapred.LocalJobRunner: reduce > reduce
15/02/25 15:30:48 INFO mapred.Task: Task 'attempt_local284822998_0001_r_000000_0' done.
15/02/25 15:30:48 INFO mapred.LocalJobRunner: Finishing task: attempt_local284822998_0001_r_000000_0
15/02/25 15:30:48 INFO mapred.LocalJobRunner: reduce task executor complete.
15/02/25 15:30:48 INFO mapreduce.Job: Job job_local284822998_0001 running in uber mode : false
15/02/25 15:30:48 INFO mapreduce.Job:  map 100% reduce 100%
15/02/25 15:30:48 INFO mapreduce.Job: Job job_local284822998_0001 completed successfully
15/02/25 15:30:48 INFO mapreduce.Job: Counters: 33
	File System Counters
		FILE: Number of bytes read=283490
		FILE: Number of bytes written=809011
		FILE: Number of read operations=0
		FILE: Number of large read operations=0
		FILE: Number of write operations=0
	Map-Reduce Framework
		Map input records=872
		Map output records=7652
		Map output bytes=75556
		Map output materialized bytes=90866
		Input split bytes=175
		Combine input records=0
		Combine output records=0
		Reduce input groups=1697
		Reduce shuffle bytes=90866
		Reduce input records=7652
		Reduce output records=1697
		Spilled Records=15304
		Shuffled Maps =1
		Failed Shuffles=0
		Merged Map outputs=1
		GC time elapsed (ms)=8
		CPU time spent (ms)=0
		Physical memory (bytes) snapshot=0
		Virtual memory (bytes) snapshot=0
		Total committed heap usage (bytes)=525336576
	Shuffle Errors
		BAD_ID=0
		CONNECTION=0
		IO_ERROR=0
		WRONG_LENGTH=0
		WRONG_MAP=0
		WRONG_REDUCE=0
	File Input Format Counters 
		Bytes Read=45119
	File Output Format Counters 
		Bytes Written=17405
$</pre><p></p>
<p>And you can take a look to the result using:</p>
<p></p><pre class="crayon-plain-tag">$ sort -k2 -h -r out/part-r-00000 | head -20
the	663
of	494
shall	293
and	256
to	183
be	178
or	157
in	139
by	101
a	94
United	85
for	81
any	79
President	72
The	64
have	64
as	64
States,	55
such	52
State	47
$</pre><p></p>
<p>Regarding this example, I have to mention a couple of things:</p>
<ol>
<li>
	The code includes a data directory containing a text file (yes, the constitution of the USA)</p>
<ul>
<li>Yes, the program need some improvements for not considering the commas and something like that.</li>
<li>It&#8217;s funny to see the most repeated words (the, of, shall, and, to, be, or, in, by, a) and the most important words (United, States, President)</li>
</ul>
</li>
<li>Due to a problem with <a href="http://wiki.apache.org/hadoop/HadoopIPv6" title="Hadoop and IPv6" target="_blank">Hadoop and IPv6</a>, it doesn&#8217;t work with pseudistributed mode due to a connection exception (<font color="red"><em>java.net.ConnectException: Call [&#8230;] to localhost:8020 failed on connection exception: java.net.ConnectException: Connection refused; For more details see:  http://wiki.apache.org/hadoop/ConnectionRefused</em></font>). For this example is enough to use local mode (just recover the original core-site.xml, hdfs-site.xml, mapred-site.xml and yarn-site.xml and you can also stop the HDFS, YARN, and MapReduce daemons. See above)</li>
</ol>
<h1>Resources</h1>
<ul>
<li><a href="http://shop.oreilly.com/product/0636920033448.do" title="Hadoop: The Definitive Guide" target="_blank">Hadoop: The Definitive Guide, 4th Edition</a>. By Tom White (O&#8217;Reilly Media)</li>
<li><a href="http://www.apress.com/9781430248637?gtmf=s" title="Pro Apache Hadoop" target="_blank">Pro Apache Hadoop, 2nd Edition</a>. By Sameer Wadkar, Madhu Siddalingaiah, Jason Venner (Apress)</li>
<li><a href="https://www.packtpub.com/big-data-and-business-intelligence/mastering-hadoop" title="Mastering Hadoop" target="_blank">Mastering Hadoop</a>. By Sandeep Karanth (Packt publishing)</li>
<li><a href="http://www.manning.com/holmes2/" title="Hadoop in Practice, Second Edition" target="_blank">Hadoop in Practice, Second Edition</a>. By Alex Holmes (Manning publications)</li>
<li><a href="http://www.manning.com/lam2/" title="Hadoop in Action, Second Edition" target="_blank">Hadoop in Action, Second Edition</a>. By Chuck P. Lam and Mark W. Davis (Manning publications)</li>
<li><a href="https://www.youtube.com/watch?v=xYnS9PQRXTg" title="Hadoop - Just the Basics for Big Data Rookies" target="_blank">Hadoop &#8211; Just the Basics for Big Data Rookies</a>. By  Adam Shook (SpringDeveloper YouTube channel)</li>
<li><a href="https://www.youtube.com/watch?v=tIPA6vMZomQ" title="Getting started with Spring Data and Apache Hadoop" target="_blank">Getting started with Spring Data and Apache Hadoop</a>. By Thomas Risberg, Janne Valkealahti (SpringDeveloper YouTube channel)</li>
<li><a href="https://www.youtube.com/watch?v=IcuTdJgUFmo" title="Hadoop 201 -- Deeper into the Elephant" target="_blank">Hadoop 201 &#8212; Deeper into the Elephant</a>. By Roman Shaposhnik (SpringDeveloper YouTube channel)</li>
<li><a href="http://hadoop.apache.org/docs/r2.6.0/hadoop-project-dist/hadoop-common/SingleCluster.html" title="Setting up a Single Node Cluster" target="_blank">Hadoop MapReduce Next Generation &#8211; Setting up a Single Node Cluster</a>.</li>
<li><a href="http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/FileSystemShell.html" title="FileSystemShell" target="_blank">The File System (FS) shell</a></li>
<li><a href="http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=mapreduce_basic" title="Primeros pasos con Hadoop: instalación y configuración en Linux" target="_blank">Primeros pasos con Hadoop: instalación y configuración en Linux</a>. By Juan Alonso Ramos (Adictos al trabajo)</li>
<li><a href="http://blog.cloudera.com/blog/2014/06/how-to-install-a-virtual-apache-hadoop-cluster-with-vagrant-and-cloudera-manager/" title="Hadoop virtual cluster: Vagrant and CDH" target="_blank">How-to: Install a Virtual Apache Hadoop Cluster with Vagrant and Cloudera Manager</a>. By Justin Kestelyn (@kestelyn Cloudera blog()</li>
<li><a href="http://hortonworks.com/blog/building-hadoop-vm-quickly-ambari-vagrant/" title="Hadoop VM: Ambari and Vagrant, HDP" target="_blank">How to build a Hadoop VM with Ambari and Vagran</a>t. By Saptak Sen (Hortonworks blog)</li>
<li><a href="http://hadoopguide.blogspot.com.es/2013/05/hadoop-hdfs-data-flow-io-classes.html" title="Hadoop HDFS Data Flow IO Classes" target="_blank">Hadoop HDFS Data Flow IO Classes</a>. By Shrey Mehrotra (Hadoop Ecosystem : Hadoop 2.x)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://malsolo.com/blog4java/?feed=rss2&#038;p=516</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Orika time!</title>
		<link>http://malsolo.com/blog4java/?p=465</link>
		<comments>http://malsolo.com/blog4java/?p=465#comments</comments>
		<pubDate>Thu, 23 Oct 2014 15:52:56 +0000</pubDate>
		<dc:creator><![CDATA[Javier (@jbbarquero)]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Springsource]]></category>
		<category><![CDATA[Mapping]]></category>
		<category><![CDATA[Orika]]></category>
		<category><![CDATA[POJO]]></category>

		<guid isPermaLink="false">http://malsolo.com/blog4java/?p=465</guid>
		<description><![CDATA[I love good software, and Orika is a really interesting project. In this post I&#8217;m going to talk about this Java bean mapping framework that I&#8217;ve used recently and I highly recommend. Orika (formerly hosted at google code) claims to &#8230; <a href="http://malsolo.com/blog4java/?p=465">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I love good software, and Orika is a really interesting project. In this post I&#8217;m going to talk about this Java bean mapping framework that I&#8217;ve used recently and I highly recommend.</p>
<p><a href="http://orika-mapper.github.io/orika-docs/" title="Orika User Guide" target="_blank">Orika</a> (formerly hosted at <a href="https://code.google.com/p/orika/" title="Orika at google code" target="_blank">google code</a>) claims to be a <em>simpler, lighter and faster Java bean mapping</em>. And it really is.</p>
<p>It allows you to convert objects by copying its attributes from one to another. It performs this by using Java introspection, instead of XML configuration or something like that. It uses code generation to create the mappers, and it has an interesting strategy for its core classes that allows you to optimize the performance.</p>
<p>It is completely configurable, for instance, the java code generator by default is Javassist, but you can use EclipseJdt or even use another provider by implementing the appropriate interface.</p>
<p>Finally, it&#8217;s a very well documented project, with clear explanations and useful code.</p>
<p>I really like it.</p>
<p>If you want to try it, just add the next dependency to your maven project:</p>
<p></p><pre class="crayon-plain-tag">&lt;dependency&gt;
			&lt;groupId&gt;ma.glasnost.orika&lt;/groupId&gt;
			&lt;artifactId&gt;orika-core&lt;/artifactId&gt;
			&lt;version&gt;1.4.5&lt;/version&gt;&lt;!-- or latest version --&gt;
		&lt;/dependency&gt;</pre><p></p>
<p>Or <a href="https://github.com/orika-mapper/orika/releases" title="Orika releases at GitHub" target="_blank">download the library</a> along with three required libraries:</p>
<ul>
<li>javassist (v 3.12.0+)</li>
<li>slf4j (v 1.5.6+)</li>
<li>paranamer (v 2.0+)</li>
</ul>
<h1>Main concepts</h1>
<p>There are two core classes, the first one is <strong>MapperFactory</strong>, the class to configure the mappings and to obtain the second core class: <strong>MapperFacade</strong>, that actually provides the service of a Java bean mapping.</p>
<h3>MapperFactory</h3>
<p>By using a fluent API, you can construct a <strong>MapperFactory</strong> via its main implementation, <strong>DefaultMapperFactory</strong> and its static class helpers intended for building the <strong>MapperFactory</strong>.</p>
<p>Then you can obtain a <strong>ClassMapBuilder</strong> from the <strong>MapperFactory</strong> in order to declare the mapping configuration in a fluent-style, that is: mapping fields (bi-directional by default, or in one direction if you&#8217;d rather), excluding fields, specifying constructors and customizing mappings of Lists, Sets, nested fields and so on.</p>
<p>There is a default mapping that maps fields with matching names between two classes, and you can also register the mapping in the MapperFactory (the ClassMapBuilder is built with the very MapperFactory as atribute). Both operations have the appropriate methods to be called.</p>
<p>Let&#8217;s see an example:</p>
<p>We have two classes: <a href="https://github.com/jbbarquero/orika-test/blob/master/src/main/java/com/malsolo/orika/test/dto/PersonDTO.java" title="PersonDTO at github" target="_blank">PersonDTO</a> and <a href="https://github.com/jbbarquero/orika-test/blob/master/src/main/java/com/malsolo/orika/test/domain/Person.java" title="Person at github" target="_blank">Person</a>, and we want to convert one object for the former class to an object of the latter one, so let&#8217;s configure the MapperFactory:</p>
<p></p><pre class="crayon-plain-tag">MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(PersonDTO.class, Person.class) //A ClassMapBuilder&lt;PersonDTO, Person&gt;
        .field(&quot;lastNames&quot;, &quot;surnames&quot;) //Register field mappings
        .field(&quot;streetAddress&quot;, &quot;address.street&quot;)
        .field(&quot;city&quot;, &quot;address.city&quot;)
        .field(&quot;postalCode&quot;, &quot;address.zipCode&quot;)
        .byDefault() //the remaining fields on both classes should be mapped matching the fields by name
        .register(); //register the mapping with the MapperFactory.</pre><p></p>
<p>The <strong>ClassMapBuilder</strong> provides interesting mappings for excluding fields, mapping fields in one direction only (as I mentioned above, mapping is by default bi-directional) and so on. See the <a href="http://orika-mapper.github.io/orika-docs/mappings-via-classmapbuilder.html" title="Declarative Mapping Configuration: using the fluent-style ClassMapBuilder API " target="_blank">Declarative Mapping Configuration</a> and <a href="http://orika-mapper.github.io/orika-docs/advanced-mappings.html" title="Advanced Mapping Configurations: beyond the basics of ClassMapBuilder API" target="_blank">Advanced Mapping Configurations</a> for more options.</p>
<h3>MapperFacade and BoundMapperFacade</h3>
<p>The <strong>MapperFacade</strong> performs the actual mapping work, for doing so, you have to obtain the MapperFacade from the MapperFactory and then use its map methods. There are two general options, <strong><em>map(objectA, B.class)</em></strong>, which will create a new instance of B.class and map the property values of objectA onto it, or <strong><em>map(objectA, objectB)</em></strong>, which copies properties from objectA onto objectB, being both of them not null.</p>
<p>Let&#8217;s see an example: </p>
<p></p><pre class="crayon-plain-tag">MapperFacade mapper = mapperFactory.getMapperFacade();
PersonDTO personDTO = new PersonDTO();
//Set values here
Person person = mapper.map(personDTO, Person.class);
//Alternatively:
//Person person = new Person();
//mapper.map(personDTO, person);</pre><p></p>
<p>The <strong>BoundMapperFacade</strong> is intended to be used with a pair of types to map and no further customization needed. It provides improved performance over use of the standard <strong>MapperFacade</strong> and it has the same usage plus a <strong><em>mapReverse</em></strong> method for mapping in the reverse direction.</p>
<p>See below an example:</p>
<p></p><pre class="crayon-plain-tag">BoundMapperFacade&lt;PersonDTO, Person&gt; boundMapper = mapperFactory.getMapperFacade(PersonDTO.class, Person.class);
PersonDTO personDTO = new PersonDTO();
//Set values here
Person person = boundMapper.map(personDTO);
//Alternatively:
//Person person = new Person();
//boundMapper.map(personDTO, person);
//Map in the reverse
PersonDTO personDTO = boundMapper.mapReverse(person);
//Alternatively with no null objects:
//boundMapper.mapReverse(person, personDTO); //curiously, it returns an A object instead of void</pre><p></p>
<p>If you’re primarily concerned with the mapping of a particular type to another, and your object graph has no cycles, use <strong>BoundMapperFacade</strong> because it has <u>better performance</u>, since you avoid the overhead of looking up an appropriate mapping strategy for the fields of the objects to be mapped, that happens when you call the map method.</p>
<h3>Performance</h3>
<p>The most expensive operations are instantiation and initialization of the MapperFactory, and the MapperFacade which is obtained from it.</p>
<p>Both of them are thread-safe objects, thus singletons or static access for them are a very recommended approach.</p>
<p>For instance, you can consider an static acces to the MapperFactory:</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.domain.mappers;

import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;

public class BaseMapper {
    final static MapperFactory MAPPER_FACTORY = new DefaultMapperFactory.Builder().build();
}</pre><p></p>
<p>And then use this class for registering class maps and access to the MapperFacade in a customize way:</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.domain.mappers;

import com.malsolo.orika.test.domain.Customer;
import com.malsolo.orika.test.dto.CustomerDTO;
import ma.glasnost.orika.MapperFacade;

public enum CustomerMapper {
    
    INSTANCE;
    
    private final MapperFacade mapperFacade;
    
    private CustomerMapper() {
        BaseMapper.MAPPER_FACTORY.classMap(CustomerDTO.class, Customer.class)
                .byDefault()
                .register();
        mapperFacade = BaseMapper.MAPPER_FACTORY.getMapperFacade();
    }
    
    public Customer map(CustomerDTO customerDTO) {
        return this.mapperFacade.map(customerDTO, Customer.class);
    }
    
    public CustomerDTO map(Customer customer) {
        return this.mapperFacade.map(customer, CustomerDTO.class);
    }
}</pre><p></p>
<p>In this case I&#8217;m using two new classes: <a href="https://github.com/jbbarquero/orika-test/blob/master/src/main/java/com/malsolo/orika/test/domain/Customer.java" title="Customer at GitHub" target="_blank">Customer</a> and <a href="https://github.com/jbbarquero/orika-test/blob/master/src/main/java/com/malsolo/orika/test/dto/CustomerDTO.java" title="CustomerDTO at GitHub" target="_blank">CustomerDTO</a>.</p>
<p>Finally, just use this helper classes:</p>
<p></p><pre class="crayon-plain-tag">CustomerDTO customerDTO = new CustomerDTO();
//Setters at will
Customer customer = CustomerMapper.INSTANCE.map(customerDTO);</pre><p></p>
<h1>How it works and Customization</h1>
<p>The best way to understand how Orika works is to read the <a href="http://orika-mapper.github.io/orika-docs/faq.html" title="Orika FAQ" target="_blank">FAQ</a>, but the source code is very clear and easy to follow, just in case  you want to take a deeper look to the details.</p>
<p><em>&#8220;Orika uses reflection to investigate the metadata of the objects to be mapped and then generates byte-code at runtime which is used to map those classes [&#8230;]&#8221;</em></p>
<p><em>&#8220;Orika mapping is configured via Java code at runtime, via a fluent-style ClassMapBuilder API. An instance is obtained from a MapperFactory which is then used to describe the mapping from one type to another. Finally, the specified ClassMap is registered with the MapperFactory for later use in generating a byte-code mapper.&#8221;</em></p>
<p>To configure Orika, the author recommends to extend the ConfigurableMapper class, and I will use this approach for using Orika with Spring (see below)</p>
<p>If you want to configure the code generation, compilation and so on, see how to do this using the MapperFactory in the next topic.</p>
<h3>MapperFactory Configuration</h3>
<p>The core class <strong>MapperFactory</strong> is instantiated as you&#8217;ve seen above, by building the provided implementation: <strong>DefaultMapperFactory</strong>. It uses a set of Strategy and factory objects for resolving constructors, for compiling code (actually, they belong to its inner static class <strong>MapperFactoryBuilder</strong> that is extended by its other inner static class that you use to instantiate the MapperFactory: the <strong>Builder</strong>), for resolving properties, and specially for building class maps.</p>
<p>So you can customize all of them after calling <strong><em>Builder</em>()</strong> and before the <strong><em>build()</em></strong> method:</p>
<p></p><pre class="crayon-plain-tag">new DefaultMapperFactory.Builder()
.constructorResolverStrategy(new SimpleConstructorResolverStrategy()) //By default, you can extend it or implement your own ConstructorResolverStrategy
.compilerStrategy(new JavassistCompilerStrategy()) //By default, you can extend it, implement your own CompilerStrategy or use EclipseJdtCompilerStrategy
.propertyResolverStrategy(new IntrospectorPropertyResolver()) //By default, you can extend it or implement your own PropertyResolverStrategy
.classMapBuilderFactory(new ClassMapBuilder.Factory()) //by default. You can use //enabled by default or //enabled by default.Factory
.useAutoMapping(true) //enabled by default
.mapNulls(true) //enabled by default
.build();</pre><p></p>
<h3>Custom Mappers</h3>
<p>A <strong><em>Mapper&lt;A, B&gt;</em></strong> copies the properties from one object onto another and it&#8217;s used internally by Orika (MapperFacade, MapperGenerator and MapperFactory use it, but it isn&#8217;t really interesting for this post, actually)</p>
<p>If you want to take control of how properties of one object instance are copied to another object instance (not null), just extends the abstract class <strong><em>CustomMapper&lt;A,B&gt;</em></strong>.</p>
<p>Then, you can register your custom mapper in the <strong>MapperFactory</strong> via its method <strong><em>registerMapper(Mapper&lt;A, B&gt; mapper)</em></strong>.</p>
<p>It&#8217;s intended to be used when the mapping behavior configured via the ClassMapBuilder API doesn’t suit your purposes, but only to copy properties, that is, the destination object already exists. If you want to control instantiation, use a CustomConverter or ObjectFactory which both return an instance. See below.</p>
<p>If you need to map nested members of the given object, you can doing so by using the current <strong>MapperFacade</strong> that it&#8217;s accessible via a protected <strong><em>mapperFacade</em></strong> variable. </p>
<p>I&#8217;ve used converters in a Spring applications as components that can be scanned and used to configure the MapperFactory by extending ConfigurableMapper as I mentioned above and I&#8217;ll show below.</p>
<h3>Object Factories</h3>
<p>An <strong><em>ObjectFactory&lt;D&gt;</em></strong> instantiates objects. You can implement this interface and register your implementation in the MapperFactory via their method <strong><em>registerObjectFactory</em></strong> (there are a couple of them)</p>
<p>I&#8217;ve never used this option.</p>
<h3>Custom Converters</h3>
<p>A <strong><em>Converter&lt;S, D&gt;</em></strong> combines both ObjectFactory and Mapper together, returning a new instance of the destination type with all properties copied from the source instance.</p>
<p>When you want to take complete control over the instantiation and mapping, just extend <strong><em>CustomConverter&lt;S, D&gt;</em></strong> to create the new instance and to provide it the properties from the source object.</p>
<p>Then, you can register your custom converter in the MapperFactory by obtaining its <strong>ConverterFactory</strong> via the <strong><em>getConverterFactory()</em></strong> method and then using one of its <strong><em>registerConverter()</em></strong> methods.</p>
<p>I&#8217;ve found this option useful when you want to create some hard conversion between classes that has the same meaning in your code but are not really related in terms of Java. Well, it&#8217;s a conversion, let&#8217;s say, from a date represented in a String and a date that has to be a Calendar. You have to use some formatter for doing so.</p>
<p>It&#8217;s also very easy to configure converters as Spring components if you need so.</p>
<h1>Using Orika with Spring</h1>
<p>Since the Orika core classes <strong>MapperFactory</strong> and the <strong>MapperFacade</strong> obtained from it are very expensive to instantiate and initialize, but at the same time are thread-safe, they should be shared as singletons. That is, they are good candidates for being Spring beans with singleton scope.</p>
<p>Let&#8217;s start with using spring-framework in a maven project,just add the next dependency to the pom.xml file:</p>
<p></p><pre class="crayon-plain-tag">&lt;dependency&gt;
			&lt;groupId&gt;org.springframework&lt;/groupId&gt;
			&lt;artifactId&gt;spring-context&lt;/artifactId&gt;
			&lt;version&gt;4.1.1.RELEASE&lt;/version&gt;&lt;!-- or latest version --&gt;
		&lt;/dependency&gt;</pre><p></p>
<h3>The Spring application</h3>
<p>Let&#8217;s create a couple of beans to obtain a Person and a PersonDTO, let&#8217;s call them service and repository respectively:</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.spring;

import com.malsolo.orika.test.domain.Person;

public interface PersonService {
    
    public Person obtainPerson();
    
}</pre><p></p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.spring;

import com.malsolo.orika.test.dto.PersonDTO;

public interface PersonRepository {
    
    public PersonDTO obtainPerson();

}</pre><p></p>
<p>And their implementations, the one for the service will use the repository interface, and the one for the repository will be a simple in-memory implementation.</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.spring;

import com.google.common.collect.ImmutableList;
import com.malsolo.orika.test.dto.PersonDTO;
import java.util.Random;
import org.springframework.stereotype.Repository;

@Repository
public class PersonRepositoryImpl implements PersonRepository {
    
    Random random = new Random();

    @Override
    public PersonDTO findPerson() {
        return this.createPersonDTO(random.nextLong());
    }

    private PersonDTO createPersonDTO(long l) {
        PersonDTO dto = new PersonDTO();
        dto.setId(l);
        //More setters here
        return dto;
    }
}</pre><p></p>
<p>Note that the service will need to convert from the DTO to the domain object, so let&#8217;s inject a mapper.</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.spring;

import com.malsolo.orika.test.domain.Person;
import ma.glasnost.orika.MapperFacade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PersonServiceImpl implements PersonService {
    
    @Autowired
    private PersonRepository personRepository;
    
    private MapperFacade mapper;

    @Autowired
    public void setMapperFactory(MapperFactory mapperFactory) {
        this.mapper = mapperFactory.getMapperFacade();
    }
    
    @Override
    public Person obtainPerson() {
        return mapper.map(this.personRepository.findPerson(), Person.class);
    }

}</pre><p></p>
<p>As you can see, I used setter injection (via autowiring) to provide a MapperFactory in order to obtain from it a MapperFacade. I&#8217;m using the suggestion of having the MapperFactory as singleton, that it&#8217;s easy to achieve with Spring.</p>
<p>Since MapperFactory has a particular way to be instantiated, the best option is to create a factory for exposing it, a FactoryBean:</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.spring;

import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

@Component
public class MapperFactoryFactory implements FactoryBean&lt;MapperFactory&gt; {

    @Override
    public MapperFactory getObject() throws Exception {
        return new DefaultMapperFactory.Builder().build();
    }

    @Override
    public Class&lt;?&gt; getObjectType() {
        return MapperFactory.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

}</pre><p></p>
<p>This approach has been selected just in case I want to use a BoundMapperFacade, but it&#8217;s possible to use a MapperFacade directly by creating a <a href="http://github" title="title" target="_blank">MapperFacadeFactory</a>.</p>
<p>Now, let&#8217;s configure the Spring application</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class OrikaSpringTest {
    
    public static void main(String... args) {
        ApplicationContext context = 
          new AnnotationConfigApplicationContext(OrikaSpringTest.class);
        PersonService personService = context.getBean(PersonService.class);
        Person person = personService.obtainPerson();
        System.out.printf(&quot;%s\n&quot;, person.toString());
    }

}</pre><p></p>
<p>This is enough for the project to run:</p>
<p></p><pre class="crayon-plain-tag">Person{id=0, name=Name 0, surnames=null, address=null}</pre><p></p>
<p>But <strong><u>pay attention</u></strong>, the mapper didn&#8217;t work, because there are differences between the two classes (tow attributes with different names, and the same concept, address, with different types)</p>
<h3>Plugging in Orika Mappers and Converters with Spring</h3>
<p>Orika provides custom converters and mappers, so the only thing we need is to configure them as spring beans in the application context. Let&#8217;s see how to do this.</p>
<p>First, we need a custom mapper. We annotate it as component to be discovered (via component scanning) by Spring.</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.spring;

import com.malsolo.orika.test.domain.Address;
import com.malsolo.orika.test.domain.Person;
import com.malsolo.orika.test.dto.PersonDTO;
import ma.glasnost.orika.CustomMapper;
import ma.glasnost.orika.MappingContext;
import org.springframework.stereotype.Component;

@Component
public class PersonDtoToPersonMapper extends CustomMapper&lt;PersonDTO, Person&gt; {

    @Override
    public void mapAtoB(PersonDTO a, Person b, MappingContext context) {
        b.setId(a.getId());
        b.setName(a.getName());
        b.setSurnames(a.getLastNames());
        //I could use the protected mapperFacade if I need to map a particular field
        //this.mapperFacade.map(sourceObject, destinationClass);
        Address address = new Address();
        address.setStreet(a.getStreetAddress());
        address.setCity(a.getCity());
        address.setZipCode(a.getPostalCode());
        b.setAddress(address);
    }

    @Override
    public void mapBtoA(Person b, PersonDTO a, MappingContext context) {
        a.setId(b.getId());
        a.setName(b.getName());
        a.setLastNames(b.getSurnames());
        Address address = b.getAddress();
        if (address != null) {
            a.setStreetAddress(address.getStreet());
            a.setCity(address.getCity());
            a.setPostalCode(address.getZipCode());
        }
    }

}</pre><p></p>
<p>Finally, we have to plug in mappers and converters that belongs to the Spring application context, into the MapperFactory. If we extend <strong>ConfigurableMapper</strong> we will have a MapperFactory created for us, and later on, the chance to access the application context itself to look up for the custom mappers and converters that are Spring components to register them in the MapperFactory.</p>
<p>Let&#8217;s show the code:</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.spring;

import java.util.Map;
import ma.glasnost.orika.Converter;
import ma.glasnost.orika.Mapper;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.ConfigurableMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class SpringConfigurableMapper extends ConfigurableMapper {

    private ApplicationContext applicationContext;

    private MapperFactory mapperFactory;

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        addSpringMappers();
        addSpringConverter();
    }

    @Override
    protected void configure(MapperFactory factory) {
        super.configure(factory);
        this.mapperFactory = factory;
    }

    private void addSpringMappers() {
        @SuppressWarnings(&quot;rawtypes&quot;)
        final Map&lt;String, Mapper&gt; mappers = applicationContext
                .getBeansOfType(Mapper.class);
        for (final Mapper&lt;?, ?&gt; mapper : mappers.values()) {
            addMapper(mapper);
        }
    }

    private void addMapper(Mapper&lt;?, ?&gt; mapper) {
        this.mapperFactory.registerMapper(mapper);
    }

    private void addSpringConverter() {
        @SuppressWarnings(&quot;rawtypes&quot;)
		final Map&lt;String, Converter&gt; converters = applicationContext
                .getBeansOfType(Converter.class);
        for (final Converter&lt;?, ?&gt; converter : converters.values()) {
            addConverter(converter);
        }
    }

    private void addConverter(Converter&lt;?, ?&gt; converter) {
        this.mapperFactory.getConverterFactory().registerConverter(converter);
    }

}</pre><p></p>
<p>Some important things to note here:</p>
<ul>
<li>Our class SpringConfigurableMapper is a @Component</li>
<p>When Spring instantiates it, it will call its constructor that is inherited from <strong>ConfigurableMapper</strong> and it calls an init method that creates a MapperFactory and allows you to configure via the overriden method. </p>
<p>So, the first method called is <strong><em>configure(MapperFactory)</em></strong>.</p>
<p>Furthermore, don&#8217;t create your own MapperFactory as I did above, because it won&#8217;t be the one you&#8217;ll use to register the mappers and converters, on the contrary, this class will create a new MapperFactory.</p>
<li>Our class SpringConfigurableMapper has the ApplicationContext @Autowired</li>
<p>It&#8217;s the same as if you implement ApplicationContextAware, but I&#8217;d rather this approach.</p>
<p>Besides, it implies that the method will be called after all the beans have been created. Since you already have a MapperFactory, you can then search for custom components and converters that are spring beans and register them in the MapperFactory.</p>
<li>Our class extends ConfigurableMapper that implements MapperFacade</li>
<p>So, you have to slightly change the PersonServiceImpl and it&#8217;s better to not have a MapperFacadeFactory or you will have an autowiring exception because there would be two beans of the MapperFacade class:</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.orika.test.spring;

import ma.glasnost.orika.MapperFacade;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.malsolo.orika.test.domain.Person;

@Service
public class PersonServiceImpl implements PersonService {
    
    @Autowired
    private PersonRepository personRepository;
    
    @Autowired
    private MapperFacade mapper;

    @Override
    public Person obtainPerson() {
        return mapper.map(this.personRepository.findPerson(), Person.class);
    }

}</pre><p></p>
<p>Now, if you run the Orika with Spring main class, <a href="https://github.com/jbbarquero/orika-test/blob/master/src/main/java/com/malsolo/orika/test/spring/OrikaSpringTest.java" title="Orika Spring test at GitHub" target="_blank">OrikaSpringTest</a>, everything will run as expected:</p>
<p></p><pre class="crayon-plain-tag">Person{id=85, name=Name 85, surnames=[S., Surname 85], address=Address{street=My street 85, city=City 85, zipCode=code 85}}</pre><p></p>
<h1>Resources</h1>
<ul>
<li><a href="https://github.com/jbbarquero/orika-test" title="Source code at GitHub" target="_blank">Source code</a> for this post</li>
<li><a href="http://orika-mapper.github.io/orika-docs/" title="Orika user guide" target="_blank">Orika User Guide</a></li>
<li><a href="http://kenblair.net/orika-spring-easy-bean-mapping/" title="Orika and Spring Framework = easy bean mapping" target="_blank">Orika and Spring Framework = easy bean mapping</a> by Ken Blair</li>
<li><a href="http://projects.spring.io/spring-framework/#quick-start" title="Spring Framework Quick Start" target="_blank">Spring Framework Quick Start</a></li>
<li><a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#extensible-xml-meat" title="Spring Framework Reference Documentation: 35.7. Meatier examples" target="_blank">Spring Framework Reference Documentation (Meatier examples)</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://malsolo.com/blog4java/?feed=rss2&#038;p=465</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>10 useful tools for me as Java EE developer</title>
		<link>http://malsolo.com/blog4java/?p=428</link>
		<comments>http://malsolo.com/blog4java/?p=428#comments</comments>
		<pubDate>Fri, 05 Sep 2014 08:10:18 +0000</pubDate>
		<dc:creator><![CDATA[Javier (@jbbarquero)]]></dc:creator>
				<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://malsolo.com/blog4java/?p=428</guid>
		<description><![CDATA[Yes, I love trivial things in my computers as terminal appearance, desktop backgrounds (from time to time I look for wallpapers at Wallbase.cc) and some programs as Rainmeter or Fences (on Windows) See an example: But now let&#8217;s see what &#8230; <a href="http://malsolo.com/blog4java/?p=428">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Yes, I love trivial things in my computers as terminal appearance, desktop backgrounds (from time to time I look for wallpapers at <a href="http://wallbase.cc/" title="Wallbase" target="_blank">Wallbase.cc</a>) and some programs as <a href="http://rainmeter.net/" title="Rainmeter" target="_blank">Rainmeter</a> or <a href="www.stardock.com/products/fences" title="Fences" target="_blank">Fences</a> (on Windows)</p>
<p>See an example:<br />
<div id="attachment_429" style="width: 310px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2014/09/Terminal-as-console-2.jpg"><img src="http://malsolo.com/blog4java/wp-content/uploads/2014/09/Terminal-as-console-2-300x168.jpg" alt="Terminal img" width="300" height="168" class="size-medium wp-image-429" /></a><p class="wp-caption-text">Terminal kermit-green and black on Ubuntu</p></div></p>
<p>But now let&#8217;s see what tools I want to have installed in any computer I use for my daily work as Java EE developer, regardless the particular project.</p>
<p>As a side note, I alternate Operating Systems whenever I can. Windows is the prefered for most of the companies. I like Ubuntu and I love my Mac Book Pro, so I make the effort of using all of them. Besides, it allows me to test if my applications are really <a href="http://en.wikipedia.org/wiki/Write_once,_run_anywhere" title="Write Once, Run Anywhere" target="_blank">WORA</a>.</p>
<ul>
<li>A Java IDE: <a href="https://www.eclipse.org/" title="Eclise" target="_blank">Eclipse</a> (<a href="http://spring.io/tools/sts" title="STS" target="_blank">Spring Tool Suite</a>), <a href="https://netbeans.org/" title="NetBeans" target="_blank">NetBeans</a> or <a href="http://www.jetbrains.com/idea/" title="IntelliJ IDEA" target="_blank">IntelliJ IDEA</a>. Now I&#8217;m trying all of them just for fun.</li>
<li>Text editor: <a href="http://www.sublimetext.com/" title="Sublime Text" target="_blank">Sublime Text</a> is my choice, but in Windows I used to love <a href="http://www.ultraedit.com/" title="UltraEdit" target="_blank">UltraEdit</a> and I use a lot <a href="http://notepad-plus-plus.org/" title="Notepad++" target="_blank">Notepad++</a>.</li>
<li>A web browser, mainly <a href="https://www.google.com/chrome/browser/" title="Chrome" target="_blank">Chrome</a>. I use <a href="https://www.mozilla.org/en-US/firefox/new/" title="Firefox" target="_blank">Firefox</a> a lot too, and from time to time, my beloved <a href="http://www.opera.com/" title="Opera" target="_blank">Opera</a>. There&#8217;s also time for <strong>IE</strong> on Windows and <strong>Safari</strong> on OS X.</li>
<li>A password manager: <a href="http://keepass.info/" title="KeePass" target="_blank">KeePass</a> or <a href="https://agilebits.com/onepassword" title="1Password" target="_blank">1Password</a> on OS X.</li>
<li>I love to use the <strong>terminal</strong>. On Windows I use <a href="http://sourceforge.net/projects/console/files/" title="Console 2" target="_blank">Console 2</a>.</li>
<li><a href="http://www.oracle.com/technetwork/java/index.html" title="Java" target="_blank">Java</a></li>
<li><a href="http://spring.io/" title="Spring" target="_blank">Spring Framework</a></li>
<li><a href="http://maven.apache.org/" title="Maven" target="_blank">Maven</a></li>
<li><a href="http://git-scm.com/" title="Git" target="_blank">Git</a>. I love <a href="https://github.com/jbbarquero" title="GitHub" target="_blank">GitHub</a>.</li>
<li><a href="https://www.youtube.com/" title="YouTube" target="_blank">YouTube</a>. It provides me tutorials, music and some fun when I need a little rest.</li>
</ul>
<p>I also have to mention <a href="www.google.com" title="Google" target="_blank">Google</a> and <a href="http://stackoverflow.com/" title="stackoverflow" target="_blank">stackoverflow</a>, nowadays I can&#8217;t imagine to work without them.</p>
<p>And what about application servers? Since I want to title the POST <em>“10 tools…”</em> they fall from the list. But to talk about a little bit of them, in each project I have to use the application server in which the application will be deployed, but I always use <a href="http://tomcat.apache.org/" title="Tomcat" target="_blank">Tomcat</a> for local tests. For anything beyond servlets and JSPs I use open source projects (<a href="http://activemq.apache.org/" title="ActiveMQ" target="_blank">ActiveMQ</a> if I need JMS, for instance). There is always a targeted server in development environment, so I&#8217;ve never used <a href="https://glassfish.java.net/" title="GlassFish" target="_blank">GlassFish</a> or <a href="http://tomee.apache.org/apache-tomee.html" title="Apache TomEE" target="_blank">TomEE</a>, but I want to try <a href="http://wildfly.org/" title="WildFly" target="_blank">WildFly</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://malsolo.com/blog4java/?feed=rss2&#038;p=428</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introduction to Spring Batch. Part II: more on running a Job</title>
		<link>http://malsolo.com/blog4java/?p=375</link>
		<comments>http://malsolo.com/blog4java/?p=375#comments</comments>
		<pubDate>Thu, 04 Sep 2014 15:45:23 +0000</pubDate>
		<dc:creator><![CDATA[Javier (@jbbarquero)]]></dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Springsource]]></category>
		<category><![CDATA[JSR-352]]></category>
		<category><![CDATA[Spring Batch]]></category>
		<category><![CDATA[Spring Framework]]></category>

		<guid isPermaLink="false">http://malsolo.com/blog4java/?p=375</guid>
		<description><![CDATA[In the previous blog post entry, we introduced Spring Batch with a simple exposition of its features, main concepts both for configuring and running Batch Jobs. We also saw a sample application and two ways of running it: by invoking &#8230; <a href="http://malsolo.com/blog4java/?p=375">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>In the previous blog post entry, <a href="http://malsolo.com/blog4java/?p=260" title="Introduction to Spring Batch" target="_blank">we introduced Spring Batch</a> with a simple exposition of its features, main concepts both for configuring and running Batch Jobs.</p>
<p>We also saw a sample application and two ways of running it: by invoking a <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/JobLauncher.html" title="Interface JobLauncher" target="_blank">JobLauncher</a> bean or by using <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/support/CommandLineJobRunner.html" title="Class CommandLineJobRunner" target="_blank">CommandLineJobRunner</a> from the command line.</p>
<p>In this blog entry, we&#8217;ll see two additional ways to run a Spring Batch job:</p>
<ol>
<li>Using <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/JobOperator.html" title="Interface JobOperator" target="_blank">JobOperator</a>, in order to have control of the batch process, from start a job to monitoring tasks such as stopping, restarting, or summarizing a Job. We&#8217;ll only pay attention to the start operation, but once a <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/JobOperator.html" title="Interface JobOperator" target="_blank">JobOperator</a> is configured, you can use for the remaining monitoring tasks.</li>
<li>Using <a href="http://projects.spring.io/spring-boot/" title="Spring Boot" target="_blank">Spring Boot</a>, the new convention-over-configuration centric framework from the Spring team, that allows you to create with a few lines of code applications that &#8220;just run&#8221;, because Spring Boot provides a lot of features based on what you have in your classpath.</li>
</ol>
<p>As usual, all the source code is available at <a href="https://github.com/jbbarquero/spring-batch-sample" title="My Spring Batch sample at GitHub" target="_blank">GitHub</a>.</p>
<h3>Running the sample: JobOperator</h3>
<p><a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/JobOperator.html" title="Interface JobOperator" target="_blank">JobOperator</a> is an interface that provides operations <a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#JobOperator" title="JobOperator" target="_blank">for inspecting and controlling jobs</a>, mainly for a command-line client or a remote launcher like a JMX console.</p>
<p>The implementation that Spring Batch provides, <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/support/SimpleJobOperator.html" title="Class SimpleJobOperator" target="_blank">SimpleJobOperator</a>, uses <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/JobLauncher.html" title="Interface JobLauncher" target="_blank">JobLauncher</a>, <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/repository/JobRepository.html" title="Interface JobRepository" target="_blank">JobRepository</a>, <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/explore/JobExplorer.html" title="Interface JobExplorer" target="_blank">JobExplorer</a>, and <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/JobRegistry.html" title="Interface JobRegistry" target="_blank">JobRegistry</a> for performing its operations. They are created by the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.html" title="Annotation Type EnableBatchProcessing" target="_blank">@EnableBatchProcessing</a> annotation, so we can create an <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/AdditionalBatchConfiguration.java" title="AdditionalBatchConfiguration.java" target="_blank">additional batch configuration</a> file with these dependencies autowired and later import it in the <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/BatchConfiguration.java" title="BatchConfiguration.java" target="_blank">batch configuration</a> file (not without issues, due to the way Spring loads the application context, we&#8217;ll see this shortly):</p>
<p></p><pre class="crayon-plain-tag">@Configuration
public class AdditionalBatchConfiguration {

    @Autowired
    JobRepository jobRepository;
    @Autowired
    JobRegistry jobRegistry;
    @Autowired
    JobLauncher jobLauncher;
    @Autowired
    JobExplorer jobExplorer;

    @Bean
    public JobOperator jobOperator() {
        SimpleJobOperator jobOperator = new SimpleJobOperator();
        jobOperator.setJobExplorer(jobExplorer);
        jobOperator.setJobLauncher(jobLauncher);
        jobOperator.setJobRegistry(jobRegistry);
        jobOperator.setJobRepository(jobRepository);
        return jobOperator;
    }

}</pre><p></p>
<p>And the <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/context/annotation/Import.html" title="Annotation Type Import" target="_blank">@Import</a>:</p>
<p></p><pre class="crayon-plain-tag">@Configuration
@EnableBatchProcessing
@Import(AdditionalBatchConfiguration.class)
public class BatchConfiguration {

	// Omitted

}</pre><p></p>
<p>Now it seems easy to run the job with a <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/MainJobOperator.java" title="MainJobOperator.java" target="_blank">main class</a>:</p>
<p></p><pre class="crayon-plain-tag">@Component
public class MainJobOperator {

    @Autowired
    JobOperator jobOperator;

    @Autowired
    Job importUserJob;

    public static void main(String... args) throws JobParametersInvalidException, JobInstanceAlreadyExistsException, NoSuchJobException, DuplicateJobException, NoSuchJobExecutionException {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);

        MainJobOperator main = context.getBean(MainJobOperator.class);
        long executionId = main.jobOperator.start(main.importUserJob.getName(), null);

        MainHelper.reportResults(main.jobOperator, executionId);
        MainHelper.reportPeople(context.getBean(JdbcTemplate.class));

        context.close();

        System.out.printf(&quot;\nFIN %s&quot;, main.getClass().getName());

    }
}</pre><p></p>
<p>But there&#8217;s a little problem&#8230; it doesn&#8217;t work:</p>
<p></p><pre class="crayon-plain-tag">Exception in thread "main" org.springframework.batch.core.launch.NoSuchJobException: No job configuration with the name [importUserJob] was registered
	at org.springframework.batch.core.configuration.support.MapJobRegistry.getJob(MapJobRegistry.java:66)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
	at com.sun.proxy.$Proxy14.getJob(Unknown Source)
	at org.springframework.batch.core.launch.support.SimpleJobOperator.start(SimpleJobOperator.java:310)
	at com.malsolo.springframework.batch.sample.MainJobOperator.main(MainJobOperator.java:15)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

Process finished with exit code 1</pre><p></p>
<p>The problem here, <em><font color=red>No job configuration with the name [<strong>importUserJob</strong>] was registered</font></em>, is due to the way that <a href="http://docs.spring.io/spring-batch/apidocs/org/springframework/batch/core/launch/JobOperator.html#start-java.lang.String-java.lang.String-" title="API" target="_blank">JobOperator.start(String jobName, String parameters)</a> works.</p>
<p>The main difference with <a href="http://docs.spring.io/spring-batch/apidocs/org/springframework/batch/core/launch/JobLauncher.html#run-org.springframework.batch.core.Job-org.springframework.batch.core.JobParameters-" title="API" target="_blank">JobLauncher.run(Job job, JobParameters jobParameters)</a> is that the former has String as parameters while the latter uses objects directly.</p>
<p>So <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/JobOperator.html" title="Interface JobOperator" target="_blank">JobOperator</a>, actually <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/support/SimpleJobOperator.html" title="Class SimpleJobOperator" target="_blank">SimpleJobOperator</a>, has to obtain a <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/Job.html" title="Interface Job" target="_blank">Job</a> with the provided name. In order to do so, it uses the <a href="http://docs.spring.io/spring-batch/apidocs/org/springframework/batch/core/configuration/JobLocator.html#getJob-java.lang.String-" title="API" target="_blank">JobRegistry.getJob(String name)</a> method. The available Spring Batch implementation is <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/support/MapJobRegistry.html" title="Class MapJobRegistry" target="_blank">MapJobRegistry</a> that uses a ConcurrentMap to store using the job name as the key, a <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/JobFactory.html" title="Interface JobFactory" target="_blank">JobFactory</a> to create the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/Job.html" title="Interface Job" target="_blank">Job</a> when requested.</p>
<p>The problem is that this map has not been populated.</p>
<p>The first solution is easy: the JobRegistry allows you to register at runtime a JobFactory to later obtain the Job as explained above. So, we only need to create this JobFactory&#8230;</p>
<p></p><pre class="crayon-plain-tag">@Configuration
public class AdditionalBatchConfiguration {
//    Rest omitted
    @Autowired
    Job importUserJob;

    @Bean
    public JobFactory jobFactory() {
        return new ReferenceJobFactory(importUserJob);
    }
}</pre><p></p>
<p>&#8230;and register it in the main method:</p>
<p></p><pre class="crayon-plain-tag">@Component
public class MainJobOperator {

    @Autowired
    JobFactory jobFactory;
    @Autowired
    JobRegistry jobRegistry;
    @Autowired
    JobOperator jobOperator;

    @Autowired
    Job importUserJob;

    public static void main(String... args) throws JobParametersInvalidException, JobInstanceAlreadyExistsException, NoSuchJobException, DuplicateJobException, NoSuchJobExecutionException {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);

        MainJobOperator main = context.getBean(MainJobOperator.class);
        main.jobRegistry.register(main.jobFactory);
        long executionId = main.jobOperator.start(main.importUserJob.getName(), null);

        MainHelper.reportResults(main.jobOperator, executionId);
        MainHelper.reportPeople(context.getBean(JdbcTemplate.class));

        context.close();

        System.out.printf(&quot;\nFIN %s&quot;, main.getClass().getName());

    }
}</pre><p></p>
<p>And now it works:</p>
<p></p><pre class="crayon-plain-tag">***********************************************************
JobExecution: id=0, version=2, startTime=2014-09-04 13:03:37.964, endTime=2014-09-04 13:03:38.141, lastUpdated=2014-09-04 13:03:38.141, status=COMPLETED, exitStatus=exitCode=COMPLETED;exitDescription=, job=[JobInstance: id=0, version=0, Job=[importUserJob]], jobParameters=[{}]
* Steps executed:
StepExecution: id=0, version=3, name=step1, status=COMPLETED, exitStatus=COMPLETED, readCount=5, filterCount=0, writeCount=5 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription=
***********************************************************
***********************************************************
* People found:

* Found firstName: JILL, lastName: DOE in the database

* Found firstName: JOE, lastName: DOE in the database

* Found firstName: JUSTIN, lastName: DOE in the database

* Found firstName: JANE, lastName: DOE in the database

* Found firstName: JOHN, lastName: DOE in the database
***********************************************************</pre><p></p>
<p>But I don&#8217;t like this approach, it&#8217;s too manual.</p>
<p>I&#8217;d rather to populate the JobRegistry automatically, and Spring Batch provides two mechanisms for doing so, <a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#d4e1228" title="JobRegistryBeanPostProcessor" target="_blank">a bean post-processor</a>, <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/support/JobRegistryBeanPostProcessor.html" title="Class JobRegistryBeanPostProcessor" target="_blank">JobRegistryBeanPostProcessor</a>, and <a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#d4e1233" title="AutomaticJobRegistrar" target="_blank"> a component</a> that loads and unloads Jobs by creating child context and registering  jobs from those contexts as they are created, <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/support/AutomaticJobRegistrar.html" title="Class AutomaticJobRegistrar" target="_blank">AutomaticJobRegistrar</a>.</p>
<p>We&#8217;ll see the post-processor approach, because it&#8217;s very easy. Just declare the bean in the Batch configuration and run the original main class.</p>
<p></p><pre class="crayon-plain-tag">@Configuration
@EnableBatchProcessing
@Import(AdditionalBatchConfiguration.class)
public class BatchConfiguration {

	// Omitted

    @Bean
    public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
        JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
        jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
        return jobRegistryBeanPostProcessor;
    }

}</pre><p></p>
<p>The bean post processor has to be declared in this configuration file for registering the job when it&#8217;s created (this is the issue that I mentioned before, if you declare the post processor in another java file configuration, for instance in the <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/AdditionalBatchConfiguration.java" title="AdditionalBatchConfiguration.java" target="_blank">AdditionalBatchConfiguration</a> it will never receive the job bean). It uses the same <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/JobRegistry.html" title="Interface JobRegistry" target="_blank">JobRegistry</a> that uses the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/JobOperator.html" title="Interface JobOperator" target="_blank">JobOperator</a> to launch the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/Job.html" title="Interface Job" target="_blank">Job</a>. Actually the only that exists, but it&#8217;s good to know this.</p>
<p>It also works:</p>
<p></p><pre class="crayon-plain-tag">***********************************************************
JobExecution: id=0, version=2, startTime=2014-09-04 13:20:07.343, endTime=2014-09-04 13:20:07.522, lastUpdated=2014-09-04 13:20:07.522, status=COMPLETED, exitStatus=exitCode=COMPLETED;exitDescription=, job=[JobInstance: id=0, version=0, Job=[importUserJob]], jobParameters=[{}]
* Steps executed:
StepExecution: id=0, version=3, name=step1, status=COMPLETED, exitStatus=COMPLETED, readCount=5, filterCount=0, writeCount=5 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription=
***********************************************************
***********************************************************
* People found:

* Found firstName: JILL, lastName: DOE in the database

* Found firstName: JOE, lastName: DOE in the database

* Found firstName: JUSTIN, lastName: DOE in the database

* Found firstName: JANE, lastName: DOE in the database

* Found firstName: JOHN, lastName: DOE in the database
***********************************************************</pre><p></p>
<h3>Running the sample: Spring Boot</h3>
<p>We&#8217;d like to try how quickly and easy is Spring Boot for launching Spring Batch applications once we already have a functional configuration.</p>
<p>And it seems to be a piece of cake (the problem here is to know what is happening under the hood)</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.springframework.batch.sample;
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ApplicationConfiguration.class)})
@EnableAutoConfiguration
public class MainBoot {

    public static void main(String... args) {

        ApplicationContext context = SpringApplication.run(MainBoot.class);

        MainHelper.reportPeople(context.getBean(JdbcTemplate.class));

    }
}</pre><p></p>
<p>Actually, Spring Boot is out of the bounds of this topic, it deserves its own entry (even, an entire book) but we can summarize the important code here:</p>
<ul>
<li>Line 3: <a href="http://docs.spring.io/spring-boot/docs/current/api/index.html?org/springframework/boot/autoconfigure/EnableAutoConfiguration.html" title="Annotation Type EnableAutoConfiguration" target="_blank">@EnableAutoConfiguration</a>, with this annotation you want Spring Boot to instantiate the beans that you&#8217;re going to need based on the libraries on your classpath.</li>
<li>Line 8: <a href="http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/SpringApplication.html#run(java.lang.Object[], java.lang.String[])" title="API" target="_blank">the run method</a>, to bootstrap the application by passing the class itself (in our case, <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/MainBoot.java" title="MainBoot.java" target="_blank">MainBoot</a>) that serves as the primary Spring component.
</ul>
<p>It&#8217;s enough to run the Batch application:</p>
<p></p><pre class="crayon-plain-tag">.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.4.RELEASE)

2014-09-04 16:58:55.109  INFO 15646 --- [           main] c.m.s.batch.sample.MainBoot              : Starting MainBoot on jbeneito-Latitude-3540 with PID 15646 (/home/jbeneito/Documents/git/spring-batch-sample/target/classes started by jbeneito in /home/jbeneito/Documents/git/spring-batch-sample)
2014-09-04 16:58:55.237  INFO 15646 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@6366ebe0: startup date [Thu Sep 04 16:58:55 CEST 2014]; root of context hierarchy
2014-09-04 16:58:56.039  INFO 15646 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'jdbcTemplate': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=batchConfiguration; factoryMethodName=jdbcTemplate; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/malsolo/springframework/batch/sample/BatchConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=mainForSpringInfo; factoryMethodName=jdbcTemplate; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/malsolo/springframework/batch/sample/MainForSpringInfo.class]]
2014-09-04 16:58:56.691  WARN 15646 --- [           main] o.s.c.a.ConfigurationClassEnhancer       : @Bean method ScopeConfiguration.stepScope is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean Javadoc for complete details
2014-09-04 16:58:56.724  WARN 15646 --- [           main] o.s.c.a.ConfigurationClassEnhancer       : @Bean method ScopeConfiguration.jobScope is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean Javadoc for complete details
2014-09-04 16:58:56.729  INFO 15646 --- [           main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2014-09-04 16:58:56.975  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'batchConfiguration' of type [class com.malsolo.springframework.batch.sample.BatchConfiguration$$EnhancerBySpringCGLIB$$c3ec56ab] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:57.145  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [class org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$5a15b25b] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:57.238  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'transactionAttributeSource' of type [class org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:57.294  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'transactionInterceptor' of type [class org.springframework.transaction.interceptor.TransactionInterceptor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:57.301  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.config.internalTransactionAdvisor' of type [class org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:57.374  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'dataSourceConfiguration' of type [class com.malsolo.springframework.batch.sample.DataSourceConfiguration$$EnhancerBySpringCGLIB$$18a97d02] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:57.455  INFO 15646 --- [           main] o.s.j.d.e.EmbeddedDatabaseFactory        : Creating embedded database 'testdb'
2014-09-04 16:58:58.156  INFO 15646 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executing SQL script from class path resource [schema-all.sql]
2014-09-04 16:58:58.178  INFO 15646 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executed SQL script from class path resource [schema-all.sql] in 20 ms.
2014-09-04 16:58:58.178  INFO 15646 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executing SQL script from class path resource [org/springframework/batch/core/schema-hsqldb.sql]
2014-09-04 16:58:58.189  INFO 15646 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executed SQL script from class path resource [org/springframework/batch/core/schema-hsqldb.sql] in 11 ms.
2014-09-04 16:58:58.198  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'dataSource' of type [class org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory$EmbeddedDataSourceProxy] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:58.206  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$DataSourceInitializerConfiguration' of type [class org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$DataSourceInitializerConfiguration$$EnhancerBySpringCGLIB$$c0608242] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:58.257  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'spring.datasource.CONFIGURATION_PROPERTIES' of type [class org.springframework.boot.autoconfigure.jdbc.DataSourceProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:58.260  INFO 15646 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executing SQL script from URL [file:/home/jbeneito/Documents/git/spring-batch-sample/target/classes/schema-all.sql]
2014-09-04 16:58:58.262  INFO 15646 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executed SQL script from URL [file:/home/jbeneito/Documents/git/spring-batch-sample/target/classes/schema-all.sql] in 2 ms.
2014-09-04 16:58:58.263  WARN 15646 --- [           main] o.s.b.a.jdbc.DataSourceInitializer       : Could not send event to complete DataSource initialization (ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: org.springframework.context.annotation.AnnotationConfigApplicationContext@6366ebe0: startup date [Thu Sep 04 16:58:55 CEST 2014]; root of context hierarchy)
2014-09-04 16:58:58.263  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'dataSourceInitializer' of type [class org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:58.277  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration' of type [class org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$$EnhancerBySpringCGLIB$$85a27e41] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:58.320  INFO 15646 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'jobRegistry' of type [class com.sun.proxy.$Proxy25] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2014-09-04 16:58:58.795  INFO 15646 --- [           main] o.s.b.c.r.s.JobRepositoryFactoryBean     : No database type set, using meta data indicating: HSQL
2014-09-04 16:58:59.056  INFO 15646 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : No TaskExecutor has been set, defaulting to synchronous executor.
2014-09-04 16:58:59.361  INFO 15646 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executing SQL script from class path resource [org/springframework/batch/core/schema-hsqldb.sql]
2014-09-04 16:58:59.381  INFO 15646 --- [           main] o.s.jdbc.datasource.init.ScriptUtils     : Executed SQL script from class path resource [org/springframework/batch/core/schema-hsqldb.sql] in 20 ms.
2014-09-04 16:58:59.890  INFO 15646 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-09-04 16:58:59.926  INFO 15646 --- [           main] o.s.b.a.b.JobLauncherCommandLineRunner   : Running default command line with: []
2014-09-04 16:59:00.023  INFO 15646 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=importUserJob]] launched with the following parameters: [{run.id=1}]
2014-09-04 16:59:00.060  INFO 15646 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [step1]
Converting (firstName: Jill, lastName: Doe) into (firstName: JILL, lastName: DOE)
Converting (firstName: Joe, lastName: Doe) into (firstName: JOE, lastName: DOE)
Converting (firstName: Justin, lastName: Doe) into (firstName: JUSTIN, lastName: DOE)
Converting (firstName: Jane, lastName: Doe) into (firstName: JANE, lastName: DOE)
Converting (firstName: John, lastName: Doe) into (firstName: JOHN, lastName: DOE)
2014-09-04 16:59:00.162  INFO 15646 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=importUserJob]] completed with the following parameters: [{run.id=1}] and the following status: [COMPLETED]
2014-09-04 16:59:00.164  INFO 15646 --- [           main] c.m.s.batch.sample.MainBoot              : Started MainBoot in 5.963 seconds (JVM running for 8.019)
***********************************************************
* People found:

* Found firstName: JILL, lastName: DOE in the database

* Found firstName: JOE, lastName: DOE in the database

* Found firstName: JUSTIN, lastName: DOE in the database

* Found firstName: JANE, lastName: DOE in the database

* Found firstName: JOHN, lastName: DOE in the database
***********************************************************
2014-09-04 16:59:00.258  INFO 15646 --- [       Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@6366ebe0: startup date [Thu Sep 04 16:58:55 CEST 2014]; root of context hierarchy
2014-09-04 16:59:00.262  INFO 15646 --- [       Thread-1] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

Process finished with exit code 0</pre><p></p>
<p>As a side note, this class already scans for compontents, so we don’t need to make an additional scan for components, so we exclude the <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/ApplicationConfiguration.java" title="ApplicationConfiguration.java" target="_blank">ApplicationConfiguration</a> class with a filter.</p>
<p>Finally, we use the <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/MainHelper.java" title="MainHelper.java" target="_blank">MainHelper</a> class to show a summary of the results.</p>
<p>That&#8217;s all for now, because one more time this entry is growing really fast. Thus, we&#8217;ll see in the next post the last topic of Spring Batch that I want to talk about: <a href="https://jcp.org/en/jsr/detail?id=352" title="JSR 352: Batch Applications for the Java Platform" target="_blank">JSR 352</a>.</p>
<h3>Resources</h3>
<ul>
<li><a href="https://www.youtube.com/watch?v=lHCPppMlylY" title="Youtube" target="_blank">Webinar: Spring Batch 3.0.0</a> by <strong>Michael Minella</strong>. Published on Jun 18, 2014.</li>
<li><a href="https://www.youtube.com/watch?v=yKs4yPs-5yU" title="youtube" target="_blank">JSR-352, Spring Batch and You</a> by <strong>Michael Minella</strong>. Published on Feb 3, 2014.</li>
<li><a href="https://www.youtube.com/watch?v=8tiqeV07XlI" title="youtube" target="_blank">Integrating Spring Batch and Spring Integration</a> by <strong>Gunnar Hillert</strong>, <strong>Michael Minella</strong>. Published on Jul 9, 2014.</li>
<li><a href="http://www.amazon.com/Pro-Spring-Batch-Experts-Voice/dp/1430234520/ref=sr_1_1?ie=UTF8&#038;qid=1409752293&#038;sr=8-1&#038;keywords=pro+spring+batch" title="Amazon" target="_blank">Pro Spring Batch (Expert&#8217;s Voice in Spring)</a> by <strong>Michael Minella</strong>. Published on July 12, 2011 by <a href="http://www.apress.com/9781430234524" title="Apress" target="_blank">Apress</a>.</li>
<li>Spring Batch in Action by <strong>Arnaud Cogoluegnes</strong>, <strong>Thierry Templier</strong>, <strong>Gary Gregory</strong>, <strong>Olivier Bazoud</strong>. Published on October 10, 2011 by <a href="http://www.manning.com/templier/" title="Manning" target="_blank">Manning Publications</a>.</li>
<li>Spring.io GETTING STARTED GUIDE: <a href="http://spring.io/guides/gs/batch-processing/" title="GETTING STARTED: Creating a Batch Service" target="_blank">Creating a Batch Service</a>.
<li><a href="http://docs.spring.io/spring-batch/trunk/reference/html/" title="Spring Batch - Reference Documentation" target="_blank">Spring Batch &#8211; Reference Documentation</a></li>
<li><a href="http://docs.spring.io/spring-batch/apidocs/index.html?overview-summary.html" title="Spring Batch 3.0.1.RELEASE API" target="_blank">Spring Batch &#8211; API specification</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://malsolo.com/blog4java/?feed=rss2&#038;p=375</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introduction to Spring Batch</title>
		<link>http://malsolo.com/blog4java/?p=260</link>
		<comments>http://malsolo.com/blog4java/?p=260#comments</comments>
		<pubDate>Wed, 03 Sep 2014 10:58:02 +0000</pubDate>
		<dc:creator><![CDATA[Javier (@jbbarquero)]]></dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Springsource]]></category>
		<category><![CDATA[JSR-352]]></category>
		<category><![CDATA[Spring Batch]]></category>
		<category><![CDATA[Spring Framework]]></category>

		<guid isPermaLink="false">http://malsolo.com/blog4java/?p=260</guid>
		<description><![CDATA[Spring Batch is the Spring Project aimed to write Java Batch applications by using the foundations of Spring Framework. Michael T. Minella, project lead of Spring Batch and also a member of the JSR 352 (Batch Applications for the Java &#8230; <a href="http://malsolo.com/blog4java/?p=260">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><a href="http://projects.spring.io/spring-batch/" title="Spring Batch" target="_blank">Spring Batch</a> is the <a href="http://spring.io/projects" title="Spring Projects" target="_blank">Spring Project</a> aimed <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/DefaultBatchConfigurer.html" title="Class DefaultBatchConfigurer" target="_blank"></a>to write Java Batch applications by using the foundations of Spring Framework.</p>
<p><a href="http://spring.io/team/mminella" title="Michael Minella" target="_blank">Michael T. Minella</a>, project lead of Spring Batch and also a member of the <a href="https://jcp.org/en/jsr/detail?id=352" title="JSR 352" target="_blank">JSR 352 (Batch Applications for the Java Platform)</a> expert group, wrote in his book <a href="http://www.amazon.com/Pro-Spring-Batch-Experts-Voice/dp/1430234520" title="Pro Spring Batch" target="_blank">Pro Spring Batch</a> the next definition &#8220;<em>Batch processing [&#8230;] is defined as the processing of data without interaction or interruption. Once started, a batch process runs to some form of completion without any intervention</em>&#8220;.</p>
<p>Typically Batch Jobs are long-running, non-interactive and process large volumes of data, more than fits in memory or a single transaction. Thus they usually run outside office hours and include logic for handling errors   and restarting if necessary.</p>
<p>Spring Batch provides, among others, the next features:</p>
<ul>
<li>Transaction management, to allow you to focus on business processing.</li>
<li>Chunk based processing, to process a large value of data by dividing it in small pieces.</li>
<liDeclarative I/O, by providing readers and writers for a lot of scenarios.</li>
<li>Start/Stop/Restart/Skip/Retry capabilities, to handle non-interactive management of the process.</li>
<li>Web based administration interface (Spring Batch Admin), it provides an API for administering tasks.</li>
<li>Based on Spring framework, so it includes all the configuration options, including Dependency Injection.</li>
<li>Compliance with JSR 352: Batch Applications for the Java Platform.</li>
</ul>
<h3>Spring Batch concepts</h3>
<div id="attachment_266" style="width: 310px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2014/08/spring-batch-reference-model.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2014/08/spring-batch-reference-model-300x119.png" alt="The Domain Language of Batch" width="300" height="119" class="size-medium wp-image-266" /></a><p class="wp-caption-text">Batch Stereotypes</p></div>
<ul>
<li><a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#domainJob" title="Job" target="_blank">Job</a>: an entity that encapsulates an entire batch process. It is composed of one or more ordered <strong>Steps</strong> and it has some properties such as restartability.</li>
<li><a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#domainStep" title="Step" target="_blank">Step</a>: a domain object that encapsulates an independent, sequential phase of a batch job.</li>
<li><a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#readersAndWriters" title="ItemReaders and ItemWriters and  ItemProcessors" target="_blank">Item</a>: the individual piece of data that it&#8217;s been processed.</li>
<li><a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#chunkOrientedProcessing" title="Chunk-Oriented Processing" target="_blank">Chunk</a>: the processing style used by Spring Batch: read and process the item and then aggregate until reach a number of items, called &#8220;<em>chunk</em>&#8221; that will be finally written.</li>
<div id="attachment_271" style="width: 310px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2014/08/chunk-oriented-processing.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2014/08/chunk-oriented-processing-300x165.png" alt="Chunk-Oriented Processing" width="300" height="165" class="size-medium wp-image-271" /></a><p class="wp-caption-text">Chunk-Oriented Processing</p></div>
<li><a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#domainJobLauncher" title="JobLauncher" target="_blank">JobLauncher</a>: the entry point to launch Spring Batch jobs with a given set of JobParameters.</li>
<li><a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#domainJobRepository" title="JobRepository" target="_blank">JobRepository</a>: maintains all metadata related to job executions and provides CRUD operations for JobLauncher, Job, and Step implementations.</li>
</ul>
<h3>Running a Job</h3>
<p>The <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/JobLauncher.html" title="JobLauncher API" target="_blank">JobLauncher</a> interface has a basic implementation <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/support/SimpleJobLauncher.html" title="SimpleJobLauncher API" target="_blank">SimpleJobLauncher</a> whose only required dependency is a <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/repository/JobRepository.html" title="JobRepository API" target="_blank">JobRepository</a>, in order to obtain an execution, so that you can use it for executing the Job.</p>
<div id="attachment_275" style="width: 310px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2014/08/job-launcher-sequence-sync.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2014/08/job-launcher-sequence-sync-300x229.png" alt="JobLauncher" width="300" height="229" class="size-medium wp-image-275" /></a><p class="wp-caption-text">JobLauncher</p></div>
<p>You can also launch a Job asynchronously by configuring a <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/core/task/TaskExecutor.html" title="TaskExecutor API" target="_blank">TaskExecutor</a>. You can also this configuration <a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#runningJobsFromWebContainer" title="Running Jobs from within a Web Container" target="_blank">for running Jobs from within a Web Container</a>.</p>
<div id="attachment_277" style="width: 310px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2014/08/job-launcher-sequence-async.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2014/08/job-launcher-sequence-async-300x229.png" alt="Job launcher sequence async" width="300" height="229" class="size-medium wp-image-277" /></a><p class="wp-caption-text">Job launcher sequence async</p></div>
<p>A <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/JobLauncher.html" title="JobLauncher API" target="_blank">JobLauncher</a> uses the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/repository/JobRepository.html" title="JobRepository API" target="_blank">JobRepository</a> to create new <strong>JobExecution</strong> objects and run them.</p>
<div id="attachment_281" style="width: 310px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2014/08/job-repository.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2014/08/job-repository-300x265.png" alt="Job Repository" width="300" height="265" class="size-medium wp-image-281" /></a><p class="wp-caption-text">Job Repository</p></div>
<h3>Running Jobs: concepts</h3>
<p>The main concepts related with Job execution are</p>
<div id="attachment_283" style="width: 310px" class="wp-caption alignnone"><a href="http://malsolo.com/blog4java/wp-content/uploads/2014/08/jobHeirarchyWithSteps.png"><img src="http://malsolo.com/blog4java/wp-content/uploads/2014/08/jobHeirarchyWithSteps-300x220.png" alt="Job hierarchy with steps" width="300" height="220" class="size-medium wp-image-283" /></a><p class="wp-caption-text">Job hierarchy with steps</p></div>
<ul>
<li><a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/JobInstance.html" title="JobInstance API" target="_blank">JobInstance</a>: a logical run of a Job.</li>
<li><a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/JobParameter.html" title="JobParameter API" target="_blank">JobParameters</a>: a set of parameters used to start a batch job. It categorizes each JobInstance.</li>
<li><a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/JobExecution.html" title="JobExecution API" target="_blank">JobExecution</a>: physical runs of Jobs, in order to know what happens with the execution.</li>
<li><a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/StepExecution.html" title="StepExecution API" target="_blank">StepExecution</a>: a single attempt to execute a Step, that is created each time a Step is run and it also provides information regarding the result of the processing.</li>
<li><a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/item/ExecutionContext.html" title="ExecutionContext API" target="_blank">ExecutionContext</a>: a collection of key/value pairs that are persisted and controlled by the framework in order to allow developers a place to store persistent state that is scoped to a StepExecution or JobExecution.</li>
</ul>
<h3>Sample application</h3>
<p>Now we are going to see a simple sample application that reads a POJO that represents a Person from a file containing People data and after processing each  of them, that is just uppercase its attributes, saving them in a database.</p>
<p>All the code is available at <a href="https://github.com/jbbarquero/spring-batch-sample" title="My Spring Batch sample at GitHub" target="_blank">GitHub</a>. </p>
<p>Let&#8217;s begin with the basic domain class: <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/Person.java" title="Person.java" target="_blank">Person</a>, just a POJO.</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.springframework.batch.sample;

public class Person {
    private String lastName;
    private String firstName;
    //...
}</pre><p></p>
<p>Then, let&#8217;s see the simple processor, <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/PersonItemProcessor.java" title="PersonItemProcessor.java" target="_blank">PersonItemProcessor</a>. It implements an <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/item/ItemProcessor.html" title="ItemProcessor API" target="_blank">ItemProcessor</a>, with a Person both as Input and Output.</p>
<p>It provides a method to be overwritten, <strong>process</strong>, that allows you to write the custom transformation.</p>
<p></p><pre class="crayon-plain-tag">package com.malsolo.springframework.batch.sample;

import org.springframework.batch.item.ItemProcessor;

public class PersonItemProcessor implements ItemProcessor&lt;Person, Person&gt; {

    @Override
    public Person process(final Person person) throws Exception {
        final String firstName = person.getFirstName().toUpperCase();
        final String lastName = person.getLastName().toUpperCase();

        final Person transformedPerson = new Person(firstName, lastName);

        System.out.println(&quot;Converting (&quot; + person + &quot;) into (&quot; + transformedPerson + &quot;)&quot;);

        return transformedPerson;
    }

}</pre><p></p>
<p>Once done this, we can proceed to configure the Spring Batch Application, for doing so, we&#8217;ll use Java Annotations in a <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/BatchConfiguration.java" title="BatchConfiguration.java" target="_blank">BatchConfiguration</a> file:</p>
<p></p><pre class="crayon-plain-tag">// Imports and package omitted
@Configuration
@EnableBatchProcessing
@Import(AdditionalBatchConfiguration.class)
public class BatchConfiguration {

	// Input, processor, and output definition
	
	@Bean
    public ItemReader&lt;Person&gt; reader() {
		FlatFileItemReader&lt;Person&gt; reader = new FlatFileItemReader&lt;Person&gt;();
		reader.setResource(new ClassPathResource(&quot;sample-data.csv&quot;));
		reader.setLineMapper(new DefaultLineMapper&lt;Person&gt;() {{
			setLineTokenizer(new DelimitedLineTokenizer() {{
				setNames(new String[] {&quot;firstName&quot;, &quot;lastName&quot;});
			}});
			setFieldSetMapper(new BeanWrapperFieldSetMapper&lt;Person&gt;() {{
				setTargetType(Person.class);
			}});
			
		}});
		return reader;
	}
	
	@Bean
    public ItemProcessor&lt;Person, Person&gt; processor() {
        return new PersonItemProcessor();
    }
	
	@Bean
    public ItemWriter&lt;Person&gt; writer(DataSource dataSource) {
		JdbcBatchItemWriter&lt;Person&gt; writer = new JdbcBatchItemWriter&lt;Person&gt;();
		writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider&lt;Person&gt;());
		writer.setSql(&quot;INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)&quot;);
		writer.setDataSource(dataSource);
		return writer;
	}
	
	//  Actual job configuration
	
	@Bean
    public Job importUserJob(JobBuilderFactory jobs, Step s1) {
		return jobs.get(&quot;importUserJob&quot;)
				.incrementer(new RunIdIncrementer())
				.flow(s1)
				.end()
				.build();
	}
	
	@Bean
    public Step step1(StepBuilderFactory stepBuilderFactory, ItemReader&lt;Person&gt; reader,
            ItemWriter&lt;Person&gt; writer, ItemProcessor&lt;Person, Person&gt; processor) {
		return stepBuilderFactory.get(&quot;step1&quot;)
				.&lt;Person, Person&gt; chunk(10)
				.reader(reader)
				.processor(processor)
				.writer(writer)
				.build();
	}
	
	@Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
	
}</pre><p></p>
<p>Highlights for this class are:</p>
<ul>
<li>Line 2: <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/context/annotation/Configuration.html" title="Configuration API" target="_blank">@Configuration</a>, this class will be processed by the <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-java-basic-concepts" title="Java-based container configuration, basic concepts." target="_blank">Spring container to generate bean definitions</a>.</li>
<li>Line 3: <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.html" title="EnableBatchProcessing API" target="_blank">@EnableBatchProcessing</a>, provides a base configuration for building batch jobs <a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#javaConfig" title="Spring Batch Java Config" target="_blank">by creating the next beans beans available to be autowired</a>:
<ul>
<li>JobRepository &#8211; bean name &#8220;jobRepository&#8221;</li>
<li>JobLauncher &#8211; bean name &#8220;jobLauncher&#8221;</li>
<li>JobRegistry &#8211; bean name &#8220;jobRegistry&#8221;</li>
<li>PlatformTransactionManager &#8211; bean name &#8220;transactionManager&#8221;</li>
<li>JobBuilderFactory &#8211; bean name &#8220;jobBuilders&#8221;</li>
<li>StepBuilderFactory &#8211; bean name &#8220;stepBuilders&#8221;</li>
</ul>
<p>We&#8217;ll see shortly how it works.</li>
<li>Line 10: the <strong>reader bean</strong>, an instance of a <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/item/file/FlatFileItemReader.html" title="Class FlatFileItemReader&lt;T&gt;" target="_blank">FlatFileItemReader</a>, that implements the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/item/ItemReader.html" title="Interface ItemReader&lt;T&gt;" target="_blank">ItemReader</a> interface to read each <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/Person.java" title="Person.java" target="_blank">Person</a> from the file containing people. Spring Batch provides several implementations for this interface, being this implementation that read lines from one Resource one of them.You know, <u>no need of custom code</u>.</li>
<li>Line 26: the <strong>processor bean</strong>, an instance of the previously defined <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/PersonItemProcessor.java" title="PersonItemProcessor.java" target="_blank">PersonItemProcessor</a>. See above.</li>
<li>Line 31: the <strong>writer bean</strong>, an instance of a <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/item/database/JdbcBatchItemWriter.html" title="Class JdbcBatchItemWriter&lt;T&gt;" target="_blank">JdbcBatchItemWriter</a>, that implements the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/item/ItemWriter.html" title="Interface ItemWriter&lt;T&gt;" target="_blank">ItemWriter interface</a> to write the People already processed to the database. It&#8217;s also an implementation provided by Spring Batch, so <u>no need of custom code</u> again. In this case, you only have to provide an SQL, and a callback for the parameters. Since we are using named parameters, we&#8217;ve chosen a <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/item/database/BeanPropertyItemSqlParameterSourceProvider.html" title="Class BeanPropertyItemSqlParameterSourceProvider&lt;T&gt;" target="_blank">BeanPropertyItemSqlParameterSourceProvider</a>. This bean also needs a DataSource, so we provided it by passing one as a method parameter in order to Spring inject the instance that it has registered.</li>
<li>Line 42: a <strong><a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/Job.html" title="Interface Job" target="_blank">Job</a> bean</strong>, that it&#8217;s built using the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/JobBuilderFactory.html" title="Class JobBuilderFactory" target="_blank">JobBuilderFactory</a> that is autowired by passing it as method parameter for this @Bean method. When you call its get method, Spring Batch will create a <strong>job builder</strong> and will initialize its job repository, the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/job/builder/JobBuilder.html" title="Class JobBuilder" target="_blank">JobBuilder</a> is the convenience class for building jobs of various kinds as you can see in the code above. We also use a <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/Step.html" title="Interface Step" target="_blank">Step</a> that is configured as the next Spring bean.</li>
<li>Line 51: a <strong><a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/Step.html" title="Interface Step" target="_blank">Step</a> bean</strong>, that it’s built using the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/StepBuilderFactory.html" title="Class StepBuilderFactory" target="_blank">StepBuilderFactory</a> that is autowired by passing it as method parameter for this @Bean method, as well as the other dependencies: the <strong>reader</strong>, the <strong>processor</strong> and the <strong>writer</strong> previously defined. When calling the get method from the StepBuilderFactory, Spring Batch will create a step builder and will initialize its job repository and transaction manager, the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/step/builder/StepBuilder.html" title="Class StepBuilder" target="_blank">StepBuilder</a> is an entry point for building all kinds of steps as you can see in the code above.
</ul>
<p>This configuration is almost everything needed to configure a Batch process as defined in the concepts above.</p>
<p>Actually, only one configuration class needs to have the @EnableBatchProcessing annotation in order to have the base configuration for building batch jobs. Then you can define the job with their steps and the readers/processors/writers that they need.</p>
<p>But an additional data source is needed to be used by the <strong>JobRepository</strong>. For this sample we&#8217;ll use an in-memory one:</p>
<p></p><pre class="crayon-plain-tag">@Configuration
public class DataSourceConfiguration {

    @Bean
    public DataSource dataSource() {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        return builder
                .setType(HSQL)
                .addScript(&quot;schema-all.sql&quot;)
                .addScript(&quot;org/springframework/batch/core/schema-hsqldb.sql&quot;)
                .build();
    }

}</pre><p></p>
<p>In this case we&#8217;ll use the same in-memory database, HSQL, with the schema for the application (line 9) and the schema for the job repository (line 10). The former is available as a resource of the application, the file called <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/resources/schema-all.sql" title="src/main/resources/schema-all.sql" target="_blank">schema-all.sql</a>, and the latter in the spring-batch-core jar (spring-batch-core-3.0.1.RELEASE.jar at the time of this writing)</p>
<h3>Alternate Configuration</h3>
<p>The official documentation shows an slightly different <a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#javaConfig" title="Java Config" target="_blank">configuration</a> by using the <a href="http://docs.spring.io/spring/docs/4.0.6.RELEASE/javadoc-api/index.html?org/springframework/beans/factory/annotation/Autowired.html" title="Annotation Type Autowired" target="_blank">@Autowired</a> annotation for the beans that <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/step/builder/StepBuilder.html" title="Annotation Type EnableBatchProcessing" target="_blank">@EnableBatchProcessing</a> will create. Use the one that you like most. In this case they also imports the data base configuration.</p>
<p></p><pre class="crayon-plain-tag">@Configuration
@EnableBatchProcessing
@Import(DataSourceConfiguration.class)
public class AppConfig {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    // Input, processor, and output definition omitted

    @Bean
    public Job importUserJob() {
        return jobs.get(&quot;importUserJob&quot;).incrementer(new RunIdIncrementer()).flow(step1()).end().build();
    }

    @Bean
    protected Step step1(ItemReader&lt;Person&gt; reader, ItemProcessor&lt;Person, Person&gt; processor, ItemWriter&lt;Person&gt; writer) {
        return steps.get(&quot;step1&quot;)
            .&lt;Person, Person&gt; chunk(10)
            .reader(reader)
            .processor(processor)
            .writer(writer)
            .build();
    }

}</pre><p></p>
<p>We chose another approach: we load it when configuring the application in the main method as you&#8217;ll see shortly. besides, we imported an additional batch configuration (see line 28 at <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/BatchConfiguration.java" title="BatchConfiguration.java" target="_blank">BatchConfiguration.java</a>) to provide an alternate way to launch the application.</p>
<h3>Enable Batch Processing: how it works</h3>
<p>As we said before, we will go a little deeper in how the annotation <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.html" title="EnableBatchProcessing API" target="_blank">@EnableBatchProcessing</a> works.</p>
<p>To remind its goal, this annotation provides a base configuration for building batch jobs by creating a list of beans available to be autowired. An extract of the source code gives us a lot of information:</p>
<p></p><pre class="crayon-plain-tag">@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(BatchConfigurationSelector.class)
public @interface EnableBatchProcessing {

	/**
	 * Indicate whether the configuration is going to be modularized into multiple application contexts. If true then
	 * you should not create any &amp;#64;Bean Job definitions in this context, but rather supply them in separate (child)
	 * contexts through an {@link ApplicationContextFactory}.
	 */
	boolean modular() default false;

}</pre><p></p>
<p>As you can see at line 4, this annotation <a href="http://docs.spring.io/spring/docs/4.0.6.RELEASE/javadoc-api/index.html?org/springframework/context/annotation/Import.html" title="Annotation Type Import" target="_blank">imports</a> an implementation of an <a href="http://docs.spring.io/spring/docs/4.0.6.RELEASE/javadoc-api/index.html?org/springframework/context/annotation/ImportSelector.html" title="Interface ImportSelector" target="_blank">ImportSelector</a>, one of the options to import beans in a configuration class, in particular, to selective import beans according to certain criteria.</p>
<p>This particular implementation, <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/BatchConfigurationSelector.html" title="Class BatchConfigurationSelector" target="_blank">BatchConfigurationSelector</a>, instantiates the expected beans for providing common structure for enabling and using Spring Batch based in the EnableBatchProcessing&#8217;s attribute <strong>modular</strong>.</p>
<p>There are two implementations depending on whether you want the configuration to be modularized into multiple application contexts so that they don’t interfere with each other with the naming and the uniqueness of beans (for instance, beans named <strong>reader</strong>) or not. They are <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/ModularBatchConfiguration.html" title="Class ModularBatchConfiguration" target="_blank">ModularBatchConfiguration</a> and <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/SimpleBatchConfiguration.html" title="Class SimpleBatchConfiguration" target="_blank">SimpleBatchConfiguration</a> respectively. Mainly they both do the same, but the former using an <a href="AutomaticJobRegistrar" title="Class AutomaticJobRegistrar" target="_blank">AutomaticJobRegistrar</a> which is responsible for creating separate <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/context/ApplicationContext.html" title="Interface ApplicationContext" target="_blank">ApplicationContext</a>s for register isolated jobs that are later accesible via the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/JobRegistry.html" title="nterface JobRegistry" target="_blank">JobRegistry</a>, and the latter just creates the main components as lazy proxies that only initialize when a method is called (in order to prevent configuration cycles)</p>
<p>The key concept here is that both extends <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/AbstractBatchConfiguration.html" title="Class AbstractBatchConfiguration" target="_blank">AbstractBatchConfiguration</a> that uses the core interface for this configuration: <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/BatchConfigurer.html" title="Interface BatchConfigurer" target="_blank">BatchConfigurer</a>.</p>
<p>The default implementation, <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/configuration/annotation/DefaultBatchConfigurer.html" title="Class DefaultBatchConfigurer" target="_blank">DefaultBatchConfigurer</a>, provides the beans mentioned above (jobRepository, jobLauncher, jobRegistry, transactionManager, jobBuilders and stepBuilders), for doing so it <u>doesn&#8217;t require a dataSource</u>, it&#8217;s Autowired with required to false, so it will use a Map based JobRepository if its dataSource is null, but you have take care if you have a dataSource eligible for autowiring that doesn&#8217;t contain the expected database schema for the job repository: the batch process will fail in this case.</p>
<p>Spring Boot provides another implementation, <a href="http://docs.spring.io/spring-boot/docs/current/api/index.html?org/springframework/boot/autoconfigure/batch/BasicBatchConfigurer.html" title="Class BasicBatchConfigurer" target="_blank">BasicBatchConfigurer</a>, but this is out of the scope of this entry.</p>
<p>With all this information, we already have a Spring Batch application configured, and we more or less know how this configuration is achieved using Java.</p>
<p>Now it&#8217;s time to run the application. </p>
<h3>Running the sample: JobLauncher</h3>
<p>We have all we need to launch a batch job, the Job to be launched and a JobLauncher, so wait no more and execute this main class: <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/MainJobLauncher.java" title="MainJobLauncher.java" target="_blank">MainJobLauncher</a>.</p>
<p></p><pre class="crayon-plain-tag">@Component
public class MainJobLauncher {

    @Autowired
    JobLauncher jobLauncher;

    @Autowired
    Job importUserJob;

    public static void main(String... args) throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);

        MainJobLauncher main = context.getBean(MainJobLauncher.class);

        JobExecution jobExecution = main.jobLauncher.run(main.importUserJob, new JobParameters());

        MainHelper.reportResults(jobExecution);
        MainHelper.reportPeople(context.getBean(JdbcTemplate.class));

        context.close();

    }

}</pre><p></p>
<p>First things first. This is the way I like to write main classes. Some people from Spring are used to writing main classes annotated with <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/context/annotation/Configuration.html" title="Annotation Type Configuration" target="_blank">@Configuration</a>, but I&#8217;d rather to annotate them as <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/stereotype/Component.html" title="Annotation Type Component" target="_blank">@Component</a>s in order to separate the actual application and its configuration from the classes that test the functionality.</p>
<p>As Spring component (line 1), it only needs to have the dependencies <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/beans/factory/annotation/Autowired.html" title="Annotation Type Autowired" target="_blank">@Autowired</a>.</p>
<p>That&#8217;s the reason for the <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/ApplicationConfiguration.java" title="ApplicationConfiguration.java" target="_blank">ApplicationConfiguration</a> class. It&#8217;s a <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/context/annotation/Configuration.html" title="Annotation Type Configuration" target="_blank">@Configuration</a> class that also performs a @ComponentScan from its own package, that will find the very <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/MainJobLauncher.java" title="MainJobLauncher.java" target="_blank">MainJobLauncher</a> and the remain <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/context/annotation/Configuration.html" title="Annotation Type Configuration" target="_blank">@Configuration</a> classes, because they are also <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/stereotype/Component.html" title="Annotation Type Component" target="_blank">@Component</a>s: <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/BatchConfiguration.java" title="BatchConfiguration.java" target="_blank">BatchConfiguration</a> and <a href="https://github.com/jbbarquero/spring-batch-sample/blob/master/src/main/java/com/malsolo/springframework/batch/sample/DataSourceConfiguration.java" title="DataSourceConfiguration.java" target="_blank">DataSourceConfiguration</a>.  </p>
<p>As a main class, it creates the Spring Application Context (line 12), it gets the component as a Spring bean (line 14) and then it uses its methods (or attributes in this example. Line 16)</p>
<p>Let&#8217;s back to the Batch application: the line 16 is the call to the JobLauncher that will run the Spring Batch process.</p>
<p>The remaining lines are intended to show the results, both from the job execution and the results in the database.</p>
<p>It will be something like this:</p>
<p></p><pre class="crayon-plain-tag">***********************************************************
importUserJob finished with a status of  (COMPLETED).
* Steps executed:
	step1 : exitCode=COMPLETED;exitDescription=
StepExecution: id=0, version=3, name=step1, status=COMPLETED, exitStatus=COMPLETED, readCount=5, filterCount=0, writeCount=5 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0
***********************************************************

***********************************************************
* People found:

* Found firstName: JILL, lastName: DOE in the database

* Found firstName: JOE, lastName: DOE in the database

* Found firstName: JUSTIN, lastName: DOE in the database

* Found firstName: JANE, lastName: DOE in the database

* Found firstName: JOHN, lastName: DOE in the database
***********************************************************</pre><p></p>
<h3>Running the sample: CommandLineJobRunner</h3>
<p><a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/launch/support/CommandLineJobRunner.html" title="Class CommandLineJobRunner" target="_blank">CommandLineJobRunner</a> is a main class provided by Spring Batch as the primary entry point to <a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#commandLineJobRunner" title="The CommandLineJobRunner" target="_blank">launch a Spring Batch Job</a>.</p>
<p>It requires at least two arguments: <strong>JobConfigurationXmlPath/JobConfigurationClassName</strong> and <strong>jobName</strong>. With the first, it will create an <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/context/ApplicationContext.html" title="Interface ApplicationContext" target="_blank">ApplicationContext</a> by loading a Java Configuration from a class with the same name or by loading an XML Configuration file with the same name.</p>
<p>It has a <a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#domainJobLauncher" title="JobLauncher" target="_blank">JobLauncher</a> attribute that is autowired with the application context via its <a href="http://docs.spring.io/spring/docs/current/javadoc-api/index.html?org/springframework/beans/factory/config/AutowireCapableBeanFactory.html" title="Interface AutowireCapableBeanFactory" target="_blank">AutowireCapableBeanFactory</a> exposed, that is used to autowire the bean properties by type.</p>
<p>It accepts some options (&#8220;-restart&#8221;, &#8220;-next&#8221;, &#8220;-stop&#8221;, &#8220;-abandon&#8221;) as well as parameters for the <a href="http://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#domainJobLauncher" title="JobLauncher" target="_blank">JobLauncher</a> that are converted with the <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/converter/DefaultJobParametersConverter.html" title="Class DefaultJobParametersConverter" target="_blank">DefaultJobParametersConverter</a> as <a href="http://docs.spring.io/spring-batch/apidocs/index.html?org/springframework/batch/core/converter/JobParametersConverter.html" title="Interface JobParametersConverter" target="_blank">JobParametersConverter</a> that expects a &#8216;name=value&#8217; format.</p>
<p>You can declare this main class in the manifest file, directly or using some maven plugin as maven-jar-plugin, maven-shade-plugin or even exec-maven-plugin.</p>
<p>That is, you can invoke from your command line something like this:</p>
<p><strong>$ java CommandLineJobRunner job.xml jobName parameter=value</strong></p>
<p>Well, the sample code is a maven project that you can install (it&#8217;s enough if you package the application) and it allows to manage the dependencies (the mvn dependency:copy-dependencies command copies all the dependencies in the target/dependency directory)</p>
<p>To simplify, I&#8217;ll also copy the generated jar to the same directory of the dependencies in order to invoke the java command more easily:</p>
<p></p><pre class="crayon-plain-tag">~/Documents/git/spring-batch-sample$mvn clean install
[INFO] Scanning for projects...
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...
~/Documents/git/spring-batch-sample$ mvn dependency:copy-dependencies
[INFO] Scanning for projects...
...
[INFO] Copying spring-batch-core-3.0.1.RELEASE.jar to ~/Documents/git/spring-batch-sample/target/dependency/spring-batch-core-3.0.1.RELEASE.jar
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...
~/Documents/git/spring-batch-sample$ cp target/spring-batch-sample-0.0.1-SNAPSHOT.jar ./target/dependency/
~/Documents/git/spring-batch-sample$ java -classpath "./target/dependency/*" org.springframework.batch.core.launch.support.CommandLineJobRunner com.malsolo.springframework.batch.sample.ApplicationConfiguration importUserJob
...
12:32:17.039 [main] INFO  o.s.b.c.l.support.SimpleJobLauncher 
- Job: [FlowJob: [name=importUserJob]] 
completed with the following parameters: [{}] 
and the following status: [COMPLETED]
...</pre><p></p>
<p>That&#8217;s all for now.</p>
<p>Since this entry is becoming very large, I&#8217;ll explain other ways to run Spring Batch Jobs in a next post.</p>
]]></content:encoded>
			<wfw:commentRss>http://malsolo.com/blog4java/?feed=rss2&#038;p=260</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tomcat and JSTL: sometimes I feel tired</title>
		<link>http://malsolo.com/blog4java/?p=318</link>
		<comments>http://malsolo.com/blog4java/?p=318#comments</comments>
		<pubDate>Wed, 13 Aug 2014 11:45:13 +0000</pubDate>
		<dc:creator><![CDATA[Javier (@jbbarquero)]]></dc:creator>
				<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://malsolo.com/blog4java/?p=318</guid>
		<description><![CDATA[Bazinga! tomcat 7 org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application You can dive into our beloved stackoverflow.com to find out that Tomcat doesn&#8217;t include JSTL,not even in Tomcat &#8230; <a href="http://malsolo.com/blog4java/?p=318">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><strong>Bazinga!</strong></p>
<p><font color="red">tomcat 7 org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application</font></p>
<p>You can dive into our beloved <a href="http://stackoverflow.com/" title="Stackoverflow" target="_blank">stackoverflow.com</a> to find out that <a href="http://tomcat.apache.org/whichversion.html" title="Apache Tomcat" target="_blank">Tomcat</a> doesn&#8217;t include JSTL,not even in Tomcat 8, in spite that they have an <a href="https://tomcat.apache.org/taglibs/standard/" title="Apache Taglibs" target="_blank">implementation of the JSP Standard Tag Library (JSTL)</a> specification, versions 1.0, 1.1 and 1.2.</p>
<p>Of course, I have the correct taglib in the JSPs (note the /jsp within the URI):</p><pre class="crayon-plain-tag">&lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot; %&gt;</pre><p></p>
<p>I don&#8217;t want to include the JSTL jar included in the war, because it works in <a href="https://glassfish.java.net/" title="GlassFish - World's first Java EE 7 Application Server" target="_blank">GlassFish</a> (time to move to this server, or even try <a href="http://wildfly.org/" title="The new and improved JBoss Application Server!" target="_blank">WildFly</a>). Find <a href="http://stackoverflow.com/a/10674054/825336" title="Tomcat 7 and JSTL at Stackoverflow" target="_blank">here</a> some interesting instructions if it is not your case.</p>
<p>Thus, it&#8217;s time to copy the JSTL.jar (<a href="http://mvnrepository.com/artifact/jstl/jstl/1.2" title="jstl.jstl.1.2" target="_blank">available</a> <a href="http://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl/1.2" title="javax.servlet.jsp.jstl.jstl.1.2" target="_blank">almost</a> <a href="http://mvnrepository.com/artifact/javax.servlet/jstl/1.2" title="javax.servlet.jstl.1.2" target="_blank">anywhere</a>)</p>
<p>In NetBeans, you can go to Services (Window -> Services), find the Servers entry, right click in Apache Tomcat 8.0.3.0 to see its properties. This is the long way to discover where Tomcat is installed. In my case: <em><strong>/usr/local/apache-tomcat-8.0.3</strong></em>.</p>
<p>So I copied one of the available maven dependencies that I used to have and after restarting Tomcat, everything went OK.</p>
<p></p><pre class="crayon-plain-tag">$ cd /usr/local/apache-tomcat-8.0.3
$ sudo cp ~/.m2/repository/javax/servlet/jstl/1.2/jstl-1.2.jar .</pre><p></p>
]]></content:encoded>
			<wfw:commentRss>http://malsolo.com/blog4java/?feed=rss2&#038;p=318</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring logging with SLF4J and Logback</title>
		<link>http://malsolo.com/blog4java/?p=309</link>
		<comments>http://malsolo.com/blog4java/?p=309#comments</comments>
		<pubDate>Tue, 12 Aug 2014 12:30:26 +0000</pubDate>
		<dc:creator><![CDATA[Javier (@jbbarquero)]]></dc:creator>
				<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://malsolo.com/blog4java/?p=309</guid>
		<description><![CDATA[As you already know, Spring framework uses Commons Logging (JCL, the J stands for Jakarta, the former house for Apache Java solutions) as the framework for logging, mainly for historical reasons and backward compatibility. But it&#8217;s possible to use another &#8230; <a href="http://malsolo.com/blog4java/?p=309">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>As you already know, <a href="http://projects.spring.io/spring-framework/" title="Spring Framework" target="_blank">Spring framework</a> uses <a href="http://commons.apache.org/proper/commons-logging/" title="Apache Commons Logging" target="_blank">Commons Logging</a> (JCL, the J stands for <a href="http://jakarta.apache.org/" title="2011/12/21 - Jakarta has been retired." target="_blank">Jakarta</a>, the former house for Apache Java solutions) as the framework for logging, mainly for historical reasons and backward compatibility.</p>
<p>But it&#8217;s possible to use another framework easily thanks to the existing binding process for most of the popular frameworks.</p>
<h3>Log4J</h3>
<p>If you want to use the classic and popular framework it&#8217;s very easy, since <a href="http://logging.apache.org/log4j/1.2/" title="Apache log4j 1.2" target="_blank">Log4J</a> can be used directly with JCL (I&#8217;d rather commons-logging, BTW)</p>
<p>Just add the dependency, no need of excluding anything from Spring. For instance, in a maven project:</p><pre class="crayon-plain-tag">&lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework&lt;/groupId&gt;
            &lt;artifactId&gt;spring-context&lt;/artifactId&gt;
            &lt;version&gt;4.0.6.RELEASE&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;log4j&lt;/groupId&gt;
            &lt;artifactId&gt;log4j&lt;/artifactId&gt;
            &lt;version&gt;1.2.17&lt;/version&gt;
        &lt;/dependency&gt;</pre><p></p>
<p>Don&#8217;t forget to put a configuration file ( log4j.properties or log4j.xml) in the <a href="https://github.com/jbbarquero/spring-mvc-sample/blob/master/src/main/resources/log4j.xml" title="log4j.xml sample" target="_blank">root of the classpath</a>.</p>
<h3>SLF4J with Logback</h3>
<p>These two frameworks have became my favourite ones for Java logging. </p>
<p>However, in order to use them, you have to make a little bit more changes.</p>
<ol>
<li>Exclude CL from Spring</li>
<li><a href="http://www.slf4j.org/legacy.html" title="Bridging legacy APIs" target="_blank">Bridging legacy logging APIs</a>, that is, <a href="http://www.slf4j.org/manual.html#summary" title="SLF4J Executive summary" target="_blank">redirect</a> log4j and java.util.logging calls to SLF4J.</li>
<li>Include the <a href="http://www.slf4j.org/manual.html#swapping" title="Binding SLF4J with a logging framework at deployment time" target="_blank">SLF4J API dependency</a></li>
<li>Include the <a href="http://logback.qos.ch/manual/index.html" title="Logback" target="_blank">Logback dependency</a></li>
</ol>
<p>Since Logback implements SLF4J natively, there is no need of further binding.</p><pre class="crayon-plain-tag">&lt;dependency&gt;
            &lt;groupId&gt;org.springframework&lt;/groupId&gt;
            &lt;artifactId&gt;spring-context&lt;/artifactId&gt;
            &lt;version&gt;4.0.6.RELEASE&lt;/version&gt;
            &lt;exclusions&gt;
                &lt;exclusion&gt;
                    &lt;groupId&gt;commons-logging&lt;/groupId&gt;
                    &lt;artifactId&gt;commons-logging&lt;/artifactId&gt;
                &lt;/exclusion&gt;
            &lt;/exclusions&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
            &lt;artifactId&gt;jcl-over-slf4j&lt;/artifactId&gt;
            &lt;version&gt;1.7.7&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
            &lt;artifactId&gt;log4j-over-slf4j&lt;/artifactId&gt;
            &lt;version&gt;1.7.7&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
            &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
            &lt;version&gt;1.7.7&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;ch.qos.logback&lt;/groupId&gt;
            &lt;artifactId&gt;logback-classic&lt;/artifactId&gt;
            &lt;version&gt;1.1.2&lt;/version&gt;
        &lt;/dependency&gt;</pre><p></p>
<p>Finally, you can configure logback with a logback.groovy in the classpath, a logback-test.xml in the classpath, a <a href="https://github.com/jbbarquero/spring-core-sample/blob/master/src/main/resources/logback.xml" title="logback.xml" target="_blank">logback.xml in the classpath</a> or using the <a href="http://logback.qos.ch/manual/configuration.html#auto_configuration" title="Configuration in logback" target="_blank">BasicConfigurator</a>.</p>
<p><a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#overview-logging-slf4j" title="Using SLF4J with Spring" target="_blank">Spring provides instructions</a> to use SLF4J with Log4J and there is a great explanation for the bindings at <a href="http://blog.espenberntsen.net/2010/06/06/slf4j-logging-with-log4j-and-jcl/" title="SLF4J logging with Log4J and JCL" target="_blank">SLF4J logging with Log4J and JCL</a></p>
]]></content:encoded>
			<wfw:commentRss>http://malsolo.com/blog4java/?feed=rss2&#038;p=309</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
