<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Programming & Whisky]]></title><description><![CDATA[++drams;]]></description><link>https://blog.lukaspradel.com/</link><generator>Ghost 0.11</generator><lastBuildDate>Mon, 20 Apr 2026 12:58:45 GMT</lastBuildDate><atom:link href="https://blog.lukaspradel.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Securing Spring webservices with JSON Web Token authentication]]></title><description><![CDATA[<p>Properly securing a RESTful webservice can be challenging as REST operations are stateless by nature. Nevertheless, there are various scenarios in which at least a subset of webservice operations need to be secured. <a href="https://jwt.io/">JSON Web Tokens</a> are one way of implementing an authentication mechanism for webservices that can be used</p>]]></description><link>https://blog.lukaspradel.com/securing-spring-webservices-with-json-web-token-authentication/</link><guid isPermaLink="false">c90bc9fa-f93d-40f2-afcd-133f3ebf3ba8</guid><category><![CDATA[Java]]></category><category><![CDATA[Spring]]></category><category><![CDATA[JSON]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Fri, 28 Oct 2016 07:04:45 GMT</pubDate><content:encoded><![CDATA[<p>Properly securing a RESTful webservice can be challenging as REST operations are stateless by nature. Nevertheless, there are various scenarios in which at least a subset of webservice operations need to be secured. <a href="https://jwt.io/">JSON Web Tokens</a> are one way of implementing an authentication mechanism for webservices that can be used in conjunction with Spring Security.</p>

<p>In order to get started, we need to use some library that provides convenient JSON Web Token operations. In this example we will use JJWT:</p>

<pre><code class="language-markup">&lt;dependency&gt;  
        &lt;groupId&gt;io.jsonwebtoken&lt;/groupId&gt;
        &lt;artifactId&gt;jjwt&lt;/artifactId&gt;
        &lt;version&gt;${jjwt.version}&lt;/version&gt;
&lt;/dependency&gt;  
</code></pre>

<h3 id="configuringspringsecurity">Configuring Spring Security</h3>

<p>Next, we will configure Spring security to allow access to a login method at <code>/api/login</code> and restrict access to all webservice functions with the pattern <code>/api/secure/**</code>:</p>

<pre><code class="language-markup">&lt;!-- API Security --&gt;  
&lt;http pattern="/api/login" security="none"/&gt;

&lt;http pattern="/api/secure/**" entry-point-ref="jwtAuthenticationEntryPoint" create-session="stateless"&gt;  
    &lt;csrf disabled="true"/&gt;
    &lt;custom-filter before="FORM_LOGIN_FILTER" ref="jwtAuthenticationTokenFilter"/&gt;
&lt;/http&gt;

&lt;beans:bean id="jwtAuthenticationSuccessHandler" class="com.lukaspradel.jwt.security.JwtAuthenticationSuccessHandler" /&gt;

&lt;beans:bean id="jwtAuthenticationTokenFilter" class="com.lukaspradel.jwt.security.JwtAuthenticationTokenFilter"&gt;  
    &lt;beans:property name="authenticationManager" ref="jwtAuthMgr" /&gt;
    &lt;beans:property name="authenticationSuccessHandler" ref="jwtAuthenticationSuccessHandler" /&gt;
&lt;/beans:bean&gt;

&lt;authentication-manager id="jwtAuthMgr"&gt;  
    &lt;authentication-provider ref="jwtAuthenticationProvider" /&gt;
&lt;/authentication-manager&gt;  
</code></pre>

<p>The related classes look like this:  </p>

<pre><code class="language-java">@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint,  
        Serializable {

    private static final long serialVersionUID = 3798723588865329956L;

    @Override
    public void commence(HttpServletRequest request,
            HttpServletResponse response, AuthenticationException authException)
            throws IOException {
        // This is invoked when user tries to access a secured REST resource
        // without supplying any credentials
        // We should just send a 401 Unauthorized response because there is no
        // 'login page' to redirect to
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }
}
</code></pre>

<pre><code class="language-java">public class JwtAuthenticationSuccessHandler implements  
        AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
            HttpServletResponse response, Authentication authentication) {
        // Don't do anything specific here
    }

}
</code></pre>

<pre><code class="language-java">public class JwtAuthenticationTokenFilter extends  
        AbstractAuthenticationProcessingFilter {

    @Autowired
    private JwtProperties jwtProperties;

    public JwtAuthenticationTokenFilter() {
        super("/api/secure/**");
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
            HttpServletResponse response) {
        String header = request.getHeader(jwtProperties.getJwtHeader());

        if (header == null || !header.startsWith(jwtProperties.getJwtSchema())) {
            throw new JwtTokenMissingException(
                    "No authentication token found in request headers");
        }

        String authToken = header.substring(jwtProperties.getJwtSchema()
                .length());

        JwtAuthenticationToken authRequest = new JwtAuthenticationToken(
                authToken);

        return getAuthenticationManager().authenticate(authRequest);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain,
            Authentication authResult) throws IOException, ServletException {
        super.successfulAuthentication(request, response, chain, authResult);

        // As this authentication is in HTTP header, after success we need to
        // continue the request normally
        // and return the response as if the resource was not secured at all
        chain.doFilter(request, response);
    }
}
</code></pre>

<pre><code class="language-java">@Component
public class JwtAuthenticationProvider extends  
        AbstractUserDetailsAuthenticationProvider {

    @Autowired
    private JwtTokenValidator jwtTokenValidator;

    @Override
    public boolean supports(Class&lt;?&gt; authentication) {
        return (JwtAuthenticationToken.class.isAssignableFrom(authentication));
    }

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails,
            UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
    }

    @Override
    protected UserDetails retrieveUser(String username,
            UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) authentication;
        String token = jwtAuthenticationToken.getToken();

        CustomUserDetails parsedUser = jwtTokenValidator.parseToken(token);

        if (parsedUser == null) {
            throw new JwtTokenMalformedException("JWT token is not valid");
        }

        return new AuthenticatedUser(parsedUser.getId(),
                parsedUser.getUsername(), token, parsedUser.getAuthorities());
    }

}
</code></pre>

<p><code>JwtAuthenticationEntryPoint</code> and <code>JwtAuthenticationSuccessHandler</code> are straight forward.</p>

<p>The <code>JwtAuthenticationTokenFilter</code> verifies if the request format adheres to the JSON Web Token convention which requires the request Header to look like this:</p>

<p><code>Authorization Bearer &lt;JSON Web Token&gt;</code></p>

<p>In this example, we have simply extracted the <code>Authorization</code> and <code>Bearer</code> strings to a properties file.</p>

<p>We will look at the <code>JwtAuthenticationToken</code> class soon, for now we will inspect the <code>JwtAuthenticationProvider</code>. The purpose of this authentication provider is to perform the actual authentication. It takes the JSON Web Token parsed and passed by the <code>JwtAuthenticationTokenFilter</code> and invokes the actual authentication using an injected validator.</p>

<h3 id="theauthenticationmechanism">The authentication mechanism</h3>

<p>The <code>JwtAuthenticationToken</code> only serves to hold the actual token in a way that Spring Security understands:</p>

<pre><code class="language-java">/**
 * Holder for JWT token from the request.
 * Other fields aren't used but necessary to comply to the contracts of
 * AbstractUserDetailsAuthenticationProvider
 *
 */
public class JwtAuthenticationToken extends UsernamePasswordAuthenticationToken {

    private static final long serialVersionUID = -6181695412034946378L;

    private String token;

    public JwtAuthenticationToken(String token) {
        super(null, null);
        this.token = token;
    }

    public String getToken() {
        return token;
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    @Override
    public Object getPrincipal() {
        return null;
    }
}
</code></pre>

<p>Now, let's take a look at the actual <code>JwtTokenValidator</code>:</p>

<pre><code class="language-java">@Component
public class JwtTokenValidator {

    private static final Logger logger = LoggerFactory
            .getLogger(JwtTokenValidator.class);

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private CredentialsService credentialsService;

    public CustomUserDetails parseToken(String token) {

        CustomUserDetails userDetails = null;

        try {
            Claims body = Jwts.parser()
                    .setSigningKey(jwtProperties.getJwtSecret())
                    .parseClaimsJws(token).getBody();

            // perform credentials check with CredentialsService
        } catch (JwtException e) {
            logger.error("Failed to parse JWT token", e);
        }

        return userDetails;
    }
}
</code></pre>

<p>Here, we use the JJWT library to extract the relevant data from the raw JSON Web Token string and then use the <code>CredentialsService</code> to validate the credentials provided in the token. This portion will depend on what data you specify for valid JSON Web Tokens.</p>

<h3 id="loginandtokengenerationmechanism">Login and token generation mechanism</h3>

<p>We have covered the authentication step, however we have not discussed how (valid) tokens are generated in the first step. Recall that we specified the <code>/api/login</code> request path for this:</p>

<pre><code class="language-java">@RestController
@Transactional
public class WebserviceController {  
    ....
    @Autowired
    private CredentialsService credentialsService;

    @Autowired
    private JwtTokenGenerator jwtTokenGenerator;

    @RequestMapping(value = "/api/login", method = RequestMethod.POST)
    public JwtToken jsonLogin(@RequestBody JwtTokenRequest credentials) {

        JwtToken response = new JwtToken();

        CustomUserDetails userDetails = credentialsService
                .loadUserByUsername(credentials.getUsername());

        if (userDetails == null) {
            response.setError("Bad credentials");
            return response;
        }

        if (credentialsService.verifyCredentials(credentials.getPassword(),
                userDetails.getPassword())) {
            // Generate valid token
            String token = jwtTokenGenerator.generateToken(userDetails.getId(),
                    userDetails.getUsername());
            response.setToken(token);
        } else {
            response.setError("Bad credentials");
        }

        return response;
    }
}
</code></pre>

<p>Essentially, we require the user to submit his credentials using a POST request and check these for validity. If all is well, we respond with a valid, freshly generated JSON Web Token. First, let's look at the <code>JwtTokenRequest</code>:</p>

<pre><code class="language-java">public class JwtTokenRequest {

    private String username;

    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
</code></pre>

<p>In this example we require the user to simply pass his username and his password.</p>

<p>If all is well, we use the <code>JwtTokenGenerator</code> to generate a valid JSON Web Token:</p>

<pre><code class="language-java">@Component
public class JwtTokenGenerator {

    @Autowired
    private JwtProperties jwtProperties;

    public String generateToken(Long id, String username) {

        Claims claims = Jwts.claims().setSubject(username);
        // put further claims as needed

        LocalDateTime oneDayFromNow = LocalDateTime.now().plusHours(
                jwtProperties.getJwtValidHours());
        Date expirationDate = Date.from(oneDayFromNow.atZone(
                (ZoneId.systemDefault())).toInstant());

        return Jwts
                .builder()
                .setClaims(claims)
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512,
                        jwtProperties.getJwtSecret()).compact();
    }
}
</code></pre>

<p>Adjust the claims to the data you specified for your JSON Web Tokens. The actual JSON Web Token algorithm is implemented by JJWT. The claims you specify here correspond to the extraction performed in the <code>JwtTokenValidator</code> that we covered earlier.</p>

<p>Finally, the <code>JwtToken</code> POJO that is used to map our response to JSON is again just a holder for the token string:</p>

<pre><code class="language-java">public class JwtToken {

    private String error;

    private String token;

    public JwtToken() {
    }

    public JwtToken(String token) {
        this.token = token;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }
}
</code></pre>

<h3 id="conclusion">Conclusion</h3>

<p>By combining the JSON Web Token authentication mechanism with Spring Security as demonstrated here, the specified subset of webservice functions can only be used by users who include a valid JSON Web Token in their request headers. Thus, all functions retain their stateless nature. The "statefulness" of the login "state" lies in the <em>validity</em> period of the JSON Web Tokens we generate in <code>JwtTokenGenerator</code>.</p>

<p>Overall, JSON Web Tokens provide a convenient authentication mechanism for webservices that can be integrated into Spring Security with little overhead.</p>]]></content:encoded></item><item><title><![CDATA[Dockerizing a Tomcat + PostgreSQL Java web application]]></title><description><![CDATA[<p>Generally, a docker container is meant to hold exactly one application. For a typical Java web application (in this example we assume a Tomcat 8 servlet container and a Postgres 9.4 database), this will lead to two and a half containers:</p>

<ul>
<li>The <code>web</code> container for our web application (in</li></ul>]]></description><link>https://blog.lukaspradel.com/dockerizing-a-tomcat-postgresql-java-web-application/</link><guid isPermaLink="false">cca8d535-a3b8-422c-addb-1f2afabda0f2</guid><category><![CDATA[Java]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Tue, 24 May 2016 13:59:35 GMT</pubDate><content:encoded><![CDATA[<p>Generally, a docker container is meant to hold exactly one application. For a typical Java web application (in this example we assume a Tomcat 8 servlet container and a Postgres 9.4 database), this will lead to two and a half containers:</p>

<ul>
<li>The <code>web</code> container for our web application (in the example we assume <code>.WAR</code> packaging) deployed to Tomcat</li>
<li>The <code>db</code> container for our Postgres database</li>
<li>The <code>db-data</code> container. This one is necessary because Docker containers are volatile by default. Thus, data stored in a container is lost when they are restarted, so we need a <em>volume</em> to permanently store the database data.</li>
</ul>

<p>Naturally, the applications within their respective containers need to communicate with each other. The current tool of choice to enable inter-container communication is <a href="https://docs.docker.com/compose/">Docker Compose</a>.</p>

<h3 id="directoryandfilestructure">Directory and file structure</h3>

<p>The directory structure for our Docker files looks like this:  </p>

<pre><code>project  
│   docker-compose.yml
│
└───db
    │   Dockerfile
    │
├───web
    │   Dockerfile
    │   application.war
</code></pre>

<h3 id="thedatabasecontainer">The database container</h3>

<p>We will begin with the Dockerfile of our database in <code>./db/Dockerfile</code>:  </p>

<pre><code class="language-docker">FROM postgres:9.4  
MAINTAINER lpradel

ENV POSTGRES_USER admin  
ENV POSTGRES_PASSWORD password  
ENV POSTGRES_DB app_staging  
</code></pre>

<p>In this example we are using the standard Postgres 9.4 image and configure credentials for a single user and DB.</p>

<h3 id="theapplicationcontainer">The application container</h3>

<p>The Dockerfile for our <code>web</code> container in <code>./web/Dockerfile</code> looks like this:  </p>

<pre><code class="language-docker">FROM tomcat:8-jre8  
MAINTAINER lpradel

RUN echo "export JAVA_OPTS=\"-Dapp.env=staging\"" &gt; /usr/local/tomcat/bin/setenv.sh  
COPY ./application.war /usr/local/tomcat/webapps/staging.war

CMD ["catalina.sh", "run"]  
</code></pre>

<p>The image is based on the standard Tomcat 8 image. I have included an example of how to perform basic Tomcat configuration. Here, we pass some JAVA_OPTS to the setenv.sh shell script of Tomcat.</p>

<p>Finally, our application <code>.WAR</code> is copied the to the Tomcat <code>webapps</code> directory and deployed in the <code>staging</code> context.</p>

<h3 id="dockercompose">Docker Compose</h3>

<p>The last step is orchestrating our containers in <code>./docker-compose.yml</code>:  </p>

<pre><code class="language-yaml">app-web:  
  build: ./web
  ports:
    - "8081:8080"
  links:
    - app-db

app-db:  
  build: ./db
  expose:
    - "5432"
  volumes_from:
    - app-db-data

app-db-data:  
  image: cogniteev/echo
  command: echo 'Data Container for PostgreSQL'
  volumes:
    - /var/lib/postgresql/data
</code></pre>

<p>We bind the default Tomcat port 8080 in the container to the 8081 port of our host system and expose the Postgres port 5432 to the <code>web</code> container which is linked to it. Lastly, we reference the permanent data volume as a volume for our <code>db</code> container.</p>

<h3 id="runningtheapplication">Running the application</h3>

<p>Execute the following command to start our containers:  </p>

<pre><code class="language-bash">$ docker-compose up -d 
</code></pre>

<p>To stop the containers run  </p>

<pre><code class="language-bash">$ docker-compose stop
</code></pre>

<p>A list of all docker containers is available via  </p>

<pre><code class="language-bash">$ docker ps -a
</code></pre>

<p>To open a shell in one of the containers (for example to access log files), run the following command:  </p>

<pre><code class="language-bash">$ docker exec -it &lt;container_id&gt; /bin/bash 
</code></pre>

<p>Finally, to redeploy only specific containers, use the following command:  </p>

<pre><code class="language-bash">$ docker-compose build &lt;container_id&gt;
$ docker-compose up --no-deps -d &lt;container_id&gt;
</code></pre>]]></content:encoded></item><item><title><![CDATA[Review: Auchentoshan 12]]></title><description><![CDATA[<p><strong>Auchentoshan 12</strong> <br>
<em>Lowland, 40%. 31€ (approx. 35 freedoms)</em></p>

<p><strong>Nose</strong>: Very light and inoffensive. A bit of sweetness, almost creamy. Borderline indiscriminate.</p>

<p><strong>Colour:</strong> Caramel brown.</p>

<p><strong>Taste:</strong> Light and sweet (perhaps honey). A tiny bit of sherry. Some lighter fruits. </p>

<p><strong>Finish:</strong> Very brief. A bit nutty and rather dry.</p>

<p><strong>Summary:</strong> An oddly</p>]]></description><link>https://blog.lukaspradel.com/review-auchentoshan-12/</link><guid isPermaLink="false">203588b9-9f5d-46a2-8998-870da6967441</guid><category><![CDATA[Scotch]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Sun, 01 May 2016 17:05:54 GMT</pubDate><content:encoded><![CDATA[<p><strong>Auchentoshan 12</strong> <br>
<em>Lowland, 40%. 31€ (approx. 35 freedoms)</em></p>

<p><strong>Nose</strong>: Very light and inoffensive. A bit of sweetness, almost creamy. Borderline indiscriminate.</p>

<p><strong>Colour:</strong> Caramel brown.</p>

<p><strong>Taste:</strong> Light and sweet (perhaps honey). A tiny bit of sherry. Some lighter fruits. </p>

<p><strong>Finish:</strong> Very brief. A bit nutty and rather dry.</p>

<p><strong>Summary:</strong> An oddly one-dimensional malt, almost boring. Not for me!</p>

<p><strong>Score:</strong> 76/100.</p>]]></content:encoded></item><item><title><![CDATA[GNU Terry Pratchett]]></title><description><![CDATA[<blockquote>
  <p>"A man is not dead while his name is still spoken."</p>
  
  <p><span style="font-variant: small-caps"><sup><em>- Going Postal, Chapter 4</em></sup></span></p>
</blockquote>]]></description><link>https://blog.lukaspradel.com/gnu-terry-pratchett/</link><guid isPermaLink="false">ef38630c-8426-40d7-9c10-7c1d90aff672</guid><category><![CDATA[Off-Topic]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Sat, 12 Mar 2016 04:16:59 GMT</pubDate><content:encoded><![CDATA[<blockquote>
  <p>"A man is not dead while his name is still spoken."</p>
  
  <p><span style="font-variant: small-caps"><sup><em>- Going Postal, Chapter 4</em></sup></span></p>
</blockquote>]]></content:encoded></item><item><title><![CDATA[Review: Glenfarclas 10]]></title><description><![CDATA[<p><strong>Glenfarclas 10</strong> <br>
<em>Highland, 40%. 29€ (approx. 33 freedoms)</em></p>

<p><strong>Nose</strong>: Sherry sweetness. Just a tiny bit of peat. Well balanced.</p>

<p><strong>Colour:</strong> Light gold.</p>

<p><strong>Taste:</strong> Firm body. Less sherry, light and dry. Some malt. Perhaps some dried fruits. Vanilla and some citrus.</p>

<p><strong>Finish:</strong> Medium, longer than nose and taste would suggest. Surprisingly</p>]]></description><link>https://blog.lukaspradel.com/review-glenfarclas-10/</link><guid isPermaLink="false">4db02872-282d-444c-9ba8-23fa9bb762e3</guid><category><![CDATA[Scotch]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Sun, 07 Feb 2016 08:46:05 GMT</pubDate><content:encoded><![CDATA[<p><strong>Glenfarclas 10</strong> <br>
<em>Highland, 40%. 29€ (approx. 33 freedoms)</em></p>

<p><strong>Nose</strong>: Sherry sweetness. Just a tiny bit of peat. Well balanced.</p>

<p><strong>Colour:</strong> Light gold.</p>

<p><strong>Taste:</strong> Firm body. Less sherry, light and dry. Some malt. Perhaps some dried fruits. Vanilla and some citrus.</p>

<p><strong>Finish:</strong> Medium, longer than nose and taste would suggest. Surprisingly spicy with some initial sherry sweetness.</p>

<p><strong>Summary:</strong> A pleasant entry-level malt. Glenfarclas has better to offer, although the price is great.</p>

<p><strong>Score:</strong> 80/100.</p>]]></content:encoded></item><item><title><![CDATA[Review: Woodford Reserve Distiller's Select]]></title><description><![CDATA[<p><strong>Woodford Reserve Distiller's Select</strong> <br>
<em>Kentucky Straight Bourbon, 43.2%, 32€ (approx. 35 freedoms)</em></p>

<p><strong>Nose</strong>: Plenty of vanilla. Butterscotch. Hints of dried fruits.</p>

<p><strong>Colour:</strong> Dark amber.</p>

<p><strong>Taste:</strong> Balanced and not at all offensive. Lots of butterscotch. Some apricot. A bit spicy after a few seconds.</p>

<p><strong>Finish:</strong> Medium. The caramel lingers for</p>]]></description><link>https://blog.lukaspradel.com/review-woodford-reserve-distillers-select/</link><guid isPermaLink="false">0a7e297e-8d14-43f6-a30d-afbb0dc32683</guid><category><![CDATA[Bourbon]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Mon, 28 Dec 2015 05:51:13 GMT</pubDate><content:encoded><![CDATA[<p><strong>Woodford Reserve Distiller's Select</strong> <br>
<em>Kentucky Straight Bourbon, 43.2%, 32€ (approx. 35 freedoms)</em></p>

<p><strong>Nose</strong>: Plenty of vanilla. Butterscotch. Hints of dried fruits.</p>

<p><strong>Colour:</strong> Dark amber.</p>

<p><strong>Taste:</strong> Balanced and not at all offensive. Lots of butterscotch. Some apricot. A bit spicy after a few seconds.</p>

<p><strong>Finish:</strong> Medium. The caramel lingers for a bit. A bit spicy.</p>

<p><strong>Summary:</strong> A decent entry-level bourbon. The price is a little too high.</p>

<p><strong>Score:</strong> 78/100.</p>]]></content:encoded></item><item><title><![CDATA[User-Role-Permission security pattern (RBAC) in Spring Security 4]]></title><description><![CDATA[<p>A common access control pattern in enterprise applications is role-based access control (RBAC). Here's how to do it in Spring Security 4 using a custom <code>UserDetailsService</code>.</p>

<h3 id="thesqlddl">The SQL/DDL</h3>

<p>For the scope of this article I'm assuming a PostgreSQL database.</p>

<pre><code class="language-sql">CREATE TABLE Actor  
(
    actorId serial PRIMARY KEY,
    login character varying(</code></pre>]]></description><link>https://blog.lukaspradel.com/user-role-permission-security-rbac-in-spring-security-4/</link><guid isPermaLink="false">257e4ca0-705a-406c-b3c3-578dd54e56d0</guid><category><![CDATA[Java]]></category><category><![CDATA[Spring]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Sun, 11 Oct 2015 11:55:42 GMT</pubDate><content:encoded><![CDATA[<p>A common access control pattern in enterprise applications is role-based access control (RBAC). Here's how to do it in Spring Security 4 using a custom <code>UserDetailsService</code>.</p>

<h3 id="thesqlddl">The SQL/DDL</h3>

<p>For the scope of this article I'm assuming a PostgreSQL database.</p>

<pre><code class="language-sql">CREATE TABLE Actor  
(
    actorId serial PRIMARY KEY,
    login character varying(255) UNIQUE NOT NULL,
    password character varying(255) NOT NULL,
    enabled boolean NOT NULL,
    firstName character varying(255),
    lastName character varying(255),
    email character varying(255) NOT NULL,
    created timestamp,
    lastLogin timestamp
);

CREATE TABLE Role  
(
    roleId serial PRIMARY KEY,
    name character varying(255) UNIQUE NOT NULL,
    displayName character varying(255),
    description character varying(255)
);

CREATE TABLE Permission  
(
    permissionId serial PRIMARY KEY,
    name character varying(255) UNIQUE NOT NULL,
    description character varying(255)
);

CREATE TABLE ActorRole  
(
    actorRoleId serial PRIMARY KEY,
    actorId integer REFERENCES Actor,
    roleId integer REFERENCES Role
);

CREATE TABLE RolePermission  
(
    rolePermissionId serial PRIMARY KEY,
    roleId integer REFERENCES Role,
    permissionId integer REFERENCES Permission
);
</code></pre>

<h3 id="thecustomuserdetails">The custom UserDetails</h3>

<p>Expand this class with additional attributes of your Actor entity (e.g. first name, last name, email, address, ...)  </p>

<pre><code class="language-java">public class CustomUserDetails implements UserDetails {

    private static final long serialVersionUID = 9188230014174856593L;

    private String password;
    private final String username;
    private final Set&lt;GrantedAuthority&gt; authorities;
    private final boolean accountNonExpired;
    private final boolean accountNonLocked;
    private final boolean credentialsNonExpired;
    private final boolean enabled;

    public CustomUserDetails (String username, String password,
            Collection&lt;? extends GrantedAuthority&gt; authorities) {
        this(username, password, true, true, true, true, authorities);
    }

    public CustomUserDetails (String username, String password,
            boolean enabled, boolean accountNonExpired,
            boolean credentialsNonExpired, boolean accountNonLocked,
            Collection&lt;? extends GrantedAuthority&gt; authorities) {

        if (((username == null) || "".equals(username)) || (password == null)) {
            throw new IllegalArgumentException(
                    "Cannot pass null or empty values to constructor");
        }

        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpired = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.authorities = Collections
                .unmodifiableSet(sortAuthorities(authorities));
    }

    private static SortedSet&lt;GrantedAuthority&gt; sortAuthorities(
            Collection&lt;? extends GrantedAuthority&gt; authorities) {
        Assert.notNull(authorities,
                "Cannot pass a null GrantedAuthority collection");
        // Ensure array iteration order is predictable (as per
        // UserDetails.getAuthorities() contract and SEC-717)
        SortedSet&lt;GrantedAuthority&gt; sortedAuthorities = new TreeSet&lt;GrantedAuthority&gt;(
                new AuthorityComparator());

        for (GrantedAuthority grantedAuthority : authorities) {
            Assert.notNull(grantedAuthority,
                    "GrantedAuthority list cannot contain any null elements");
            sortedAuthorities.add(grantedAuthority);
        }

        return sortedAuthorities;
    }

    private static class AuthorityComparator implements
            Comparator&lt;GrantedAuthority&gt;, Serializable {
        private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

        public int compare(GrantedAuthority g1, GrantedAuthority g2) {
            // Neither should ever be null as each entry is checked before
            // adding it to
            // the set.
            // If the authority is null, it is a custom authority and should
            // precede
            // others.
            if (g2.getAuthority() == null) {
                return -1;
            }

            if (g1.getAuthority() == null) {
                return 1;
            }

            return g1.getAuthority().compareTo(g2.getAuthority());
        }
    }

    @Override
    public Collection&lt;? extends GrantedAuthority&gt; getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return accountNonExpired;
    }

    @Override
    public boolean isAccountNonLocked() {
        return accountNonLocked;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return credentialsNonExpired;
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }
}
</code></pre>

<h3 id="thecustomuserdetailsservice">The custom UserDetailsService</h3>

<p>Adapt the <code>loadUserByUsername</code> method to feed the additional custom actor entity attributes to the <code>CustomUserDetails</code> object.</p>

<pre><code class="language-java">@Service
@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private ActorRepository actorRepository;

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {

        try {
            Actor actor = actorRepository.findByLogin(username);

            boolean enabled = true;
            boolean accountNonExpired = true;
            boolean credentialsNonExpired = true;
            boolean accountNonLocked = true;

            // adapt as needed
            return new CustomUserDetails(actor.getLogin(),
                    actor.getPassword(), enabled, accountNonExpired,
                    credentialsNonExpired, accountNonLocked,
                    getAuthorities(actor.getRoles()));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static class SimpleGrantedAuthorityComparator implements
            Comparator&lt;SimpleGrantedAuthority&gt; {

        @Override
        public int compare(SimpleGrantedAuthority o1, SimpleGrantedAuthority o2) {
            return o1.equals(o2) ? 0 : -1;
        }
    }

    /**
     * Retrieves a collection of {@link GrantedAuthority} based on a list of
     * roles
     * 
     * @param roles
     *            the assigned roles of the user
     * @return a collection of {@link GrantedAuthority}
     */
    public Collection&lt;? extends GrantedAuthority&gt; getAuthorities(Set&lt;Role&gt; roles) {

        Set&lt;SimpleGrantedAuthority&gt; authList = new TreeSet&lt;SimpleGrantedAuthority&gt;(
                new SimpleGrantedAuthorityComparator());

        for (Role role : roles) {
            authList.addAll(getGrantedAuthorities(role));
        }

        return authList;
    }

    /**
     * Wraps a {@link Role} role to {@link SimpleGrantedAuthority} objects
     * 
     * @param roles
     *            {@link String} of roles
     * @return list of granted authorities
     */
    public static Set&lt;SimpleGrantedAuthority&gt; getGrantedAuthorities(Role role) {

        Set&lt;SimpleGrantedAuthority&gt; authorities = new HashSet&lt;SimpleGrantedAuthority&gt;();

        Set&lt;Permission&gt; rolePermissions = role.getPermissions();
        for (Permission permission : rolePermissions) {
            authorities.add(new SimpleGrantedAuthority(permission.getName()));
        }

        return authorities;
    }
}
</code></pre>

<h3 id="thespringconfiguration">The Spring configuration</h3>

<p>In this example I'm using XML to configure Spring Security. Naturally this can also be done using annotations.</p>

<pre><code class="language-markup">&lt;beans:beans xmlns="http://www.springframework.org/schema/security"  
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security.xsd"&gt;

    &lt;http auto-config="true" authentication-manager-ref="adminAuthMgr"&gt;
        &lt;intercept-url pattern="/admin/**"
            access="hasAuthority('PERM_ACCESS_ADMIN_AREA')" /&gt;

        &lt;form-login login-page="/login" default-target-url="/admin/dashboard"
            authentication-failure-url="/login?error"
            username-parameter="username" password-parameter="password"
            login-processing-url="/j_spring_security_check" /&gt;
        &lt;logout logout-url="/j_spring_security_logout"
            logout-success-url="/login?logout" /&gt;
        &lt;csrf /&gt;
    &lt;/http&gt;

    &lt;authentication-manager alias="adminAuthMgr"&gt;
        &lt;authentication-provider
            user-service-ref="customUserDetailsService"&gt;
            &lt;password-encoder hash="bcrypt" /&gt;
        &lt;/authentication-provider&gt;
    &lt;/authentication-manager&gt;
&lt;/beans:beans&gt;  
</code></pre>

<h3 id="remarks">Remarks</h3>

<p>Note how you can use the <code>hasAuthority(PERM_XY)</code> or <code>hasAuthority(ROLE_ZY)</code> expression to elegantly handle that both permissions from the Permission table and roles from the Role table are stored in the permissions attribute of Spring <code>UserDetails</code>.</p>]]></content:encoded></item><item><title><![CDATA[Review: Edradour Caledonia 12]]></title><description><![CDATA[<p><strong>Edradour Caledonia 12</strong> <br>
<em>Highland, 46%, NCF. 50€ (approx. 55 freedoms)</em></p>

<p><strong>Nose</strong>: Alcoholic. Tingling and slightly stinging. Some malt, good chunk of sherry. A good bit of oak, and some honey. Adding some water definitely opens up the nose and helps with the slightly unpleasant alcohol.</p>

<p><strong>Colour:</strong> Dark amber. Uncolored according</p>]]></description><link>https://blog.lukaspradel.com/review-edradour-caledonia-12/</link><guid isPermaLink="false">ab3cb34e-d8a3-47ce-85de-e9b094e0db78</guid><category><![CDATA[Scotch]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Mon, 03 Aug 2015 10:42:26 GMT</pubDate><content:encoded><![CDATA[<p><strong>Edradour Caledonia 12</strong> <br>
<em>Highland, 46%, NCF. 50€ (approx. 55 freedoms)</em></p>

<p><strong>Nose</strong>: Alcoholic. Tingling and slightly stinging. Some malt, good chunk of sherry. A good bit of oak, and some honey. Adding some water definitely opens up the nose and helps with the slightly unpleasant alcohol.</p>

<p><strong>Colour:</strong> Dark amber. Uncolored according to label.</p>

<p><strong>Taste:</strong> Full and heavy. Rather dry. Initially some dried or toasted fruits and more honey. Malty. Then, sherry big time. Very full-bodied. Extremely spicy, even with water.</p>

<p><strong>Finish:</strong> Medium. Lots of sherry and heavy oak to the point of bitterness. Very dry.</p>

<p><strong>Summary:</strong> Certainly not a bad dram, but not my cup of whisky.
My first sherried whisky. Can't say that I'm too much of a fan of this, although I have no doubt that this is a quality dram. YMMV.</p>

<p><strong>Score:</strong> 72/100.</p>]]></content:encoded></item><item><title><![CDATA[Testing Java enum default case]]></title><description><![CDATA[<p>In certain situations it may be desirable to test the <code>default</code> case of a <code>switch</code> statement even if at the current time all possible values of the enum are covered (e.g. in case in the future a new value is added and not covered in the switch statement). Whether</p>]]></description><link>https://blog.lukaspradel.com/testing-java-enum-default-case/</link><guid isPermaLink="false">b628a8d5-49f8-4778-bf8a-5567dd055136</guid><category><![CDATA[Java]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Sun, 28 Jun 2015 08:29:27 GMT</pubDate><content:encoded><![CDATA[<p>In certain situations it may be desirable to test the <code>default</code> case of a <code>switch</code> statement even if at the current time all possible values of the enum are covered (e.g. in case in the future a new value is added and not covered in the switch statement). Whether or not this does always make sense is debatable but not the concern of this post.</p>

<p>To achieve this we must add an artificial value to our enum. For this, we use PowerMock and Mockito. Consider the following enum:</p>

<pre><code class="language-java">public enum Day {  
    MONDAY, FRIDAY 
}
</code></pre>

<p>Now, suppose an instance of <code>Day</code> is evaluated in the following method using a <code>switch</code> statement:</p>

<pre><code class="language-java">public void tellItLikeItIs(Day day) {  
    switch (day) {
        case MONDAY:
            System.out.println("Mondays are bad.");
            break;

        case FRIDAY:
            System.out.println("Fridays are better.");
            break;

        default:
            System.out.println("The other days are so-so.");
            break;
    }
}
</code></pre>

<p>In the current state of the <code>Day</code> enum, all cases are covered and the <code>default</code> statement is not executed. However we might want to ensure correct behaviour in the <code>default</code> case using a unit test in case other days are added later.</p>

<p>We implement our testing strategy as follows:</p>

<pre><code class="language-java">@PrepareForTest(Day.class)
public class DayTest extends BaseTest {

    @Mock
    private Day additionalDay;

    @Test
    public void testTellItLikeItIsDefaultCase()
    {
        Day[] values = Day.values();
        Day[] valuesAndAdditional = new Day[values.length + 1];
        System.arraycopy(values, 0, valuesAndAdditional, 0, values.length);

        // create additional, artificial Day
        PowerMockito.mockStatic(Day.class);

        Whitebox.setInternalState(additionalDay, "name", "ADDITIONAL_DAY");
        Whitebox.setInternalState(additionalDay, "ordinal", values.length);
        valuesAndAdditional[values.length] = additionalDay;

        when(Day.values()).thenReturn(
                valuesAndAdditional);

        tellItLikeItIs(additionalDay);

        // Tests for default case behaviour
        // ...
    }
</code></pre>

<p>Note that we need to annotate our Test with <code>PrepareForTest</code> bound to our enum, as we perform a static mock on it later. For our mocked enum value, we set the name and ordinal attributes accordingly as these are evaluated in the switch statement. Finally, we overwrite the return value of the <code>values</code> method of our enum to include the additional value.</p>

<p><strong>Note that at this point in time there appears to be a <a href="https://code.google.com/p/powermock/issues/detail?id=440">bug</a> in PowerMock which allows for correct mocking only when the enum-related method is executed first in the test class!</strong></p>

<p>Ensuring that the method in question is executed first depends on your specific testing framework.</p>]]></content:encoded></item><item><title><![CDATA[Installing Arch Linux on ASUS G750/G751]]></title><description><![CDATA[<p>I recently installed Arch Linux on my ASUS G751 laptop. I will share some of the problems I faced and solutions in case someone else is considering installing Arch on his G75x.</p>

<h4 id="bootingandgraphicsrendering">Booting and graphics rendering</h4>

<p>At the time of this blog post the current version of the nouveau driver</p>]]></description><link>https://blog.lukaspradel.com/installing-arch-linux-on-asus-g750g751/</link><guid isPermaLink="false">8cc5d611-21d3-47c7-8573-5ba332ea7ae4</guid><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Fri, 22 May 2015 13:37:37 GMT</pubDate><content:encoded><![CDATA[<p>I recently installed Arch Linux on my ASUS G751 laptop. I will share some of the problems I faced and solutions in case someone else is considering installing Arch on his G75x.</p>

<h4 id="bootingandgraphicsrendering">Booting and graphics rendering</h4>

<p>At the time of this blog post the current version of the nouveau driver does not support the GeForce GTX970M/GTX980M. This will change in the future. Refer to <a href="http://nouveau.freedesktop.org/wiki/FeatureMatrix/">nouveau's feature matrix</a> for the current state of card support.</p>

<p>For this reason it is necessary to disable the auto-loading of the nouveau driver by modern Linux kernels upon boot. Otherwise you will only get a blank screen. To do this, press <code>e</code> in the Arch boot menu and append the following:  </p>

<pre><code>nomodeset  
</code></pre>

<p>This will force Linux to use software graphics rendering instead of using the nouveau driver. Your machine has powerful hardware so you will have no further issues with this during installation.</p>

<h3 id="installation">Installation</h3>

<p>The installation process is no different than on any other machine. You can follow the <a href="https://wiki.archlinux.org/index.php/Installation_guide">Installation guide</a> from the wiki.</p>

<h3 id="bootloader">Bootloader</h3>

<p>The G75x devices boot using UEFI rather than MBR. In my experience using <a href="https://wiki.archlinux.org/index.php/Gummiboot">gummiboot</a> or <a href="https://wiki.archlinux.org/index.php/REFInd">rEFInd</a> will give you the least hassle to get your bootloader up and running, especially if you are going for a dual-boot setup like I did. Both will automatically detect your Windows bootloader and add a correct boot menu entry. I find GRUB to be rather complicated to configure correctly for UEFI but the choice is yours.</p>

<h3 id="graphicsdriverandkernelcompilation">Graphics driver and kernel compilation</h3>

<p>I strongly recommend using the <a href="https://wiki.archlinux.org/index.php/NVIDIA">proprietary NVIDIA drivers</a>. Furthermore I needed to either keep using the <code>nomodeset</code> in the kernel parameters of my bootloader or recompiling the kernel with the parameter. I went for the latter option. Edit your <code>/etc/mkinitcpio.conf</code> file with the editor of your choice to include the <code>nomodeset</code> parameter and then recompile using the following command:  </p>

<pre><code># mkinitcpio -p linux
</code></pre>

<h3 id="keyboardbacklight">Keyboard backlight</h3>

<p>For me, the keyboard backlight was disabled/off out of the box. You can use the appropriate multimedia keys to manipulate the backlight or install the <a href="https://aur.archlinux.org/packages/asus-kbd-backlight/">asus-kbd-backlight</a> package for control from the command line. Install the package from the AUR and hook it into systemd:  </p>

<pre><code># systemctl daemon-reload
# systemctl start asus-kbd-backlight.service
# systemctl enable asus-kbd-backlight.service
</code></pre>

<p>Usage is very straight-forward:  </p>

<pre><code>$ asus-kbd-backlight up
$ asus-kbd-backlight down
$ asus-kbd-backlight max
$ asus-kbd-backlight off
$ asus-kbd-backlight night
$ asus-kbd-backlight 2
$ asus-kbd-backlight show
</code></pre>

<h3 id="presentations">Presentations</h3>

<p>I suppose this is more of a general Arch laptop issue but I figured it might be interesting to some folks. Install the <code>xorg-xrandr</code> package or use graphical packages like <a href="https://www.archlinux.org/packages/community/any/arandr/">arandr</a>. Check the docs of the packages for further info.</p>

<h3 id="finalremarks">Final remarks</h3>

<p>The trackpad works out of the box with the newer Linux kernels. Have fun running Arch on your ASUS G75x!</p>]]></content:encoded></item><item><title><![CDATA[Review: Highland Park 12]]></title><description><![CDATA[<p><strong>Highland Park 12</strong> <br>
<em>Island, 40%</em></p>

<p><strong>Nose</strong>: Pleasant earthiness. Heather. Some malt, hints of sherry.</p>

<p><strong>Colour:</strong> Dark gold.</p>

<p><strong>Taste:</strong> Some initial sherry. Very smooth. Heather-honey sweetness. Pineapple. Ever so gentle smoke. Delicious.</p>

<p><strong>Finish:</strong> Medium. Glorious Highland Park peat. Very dry.</p>

<p><strong>Summary:</strong> A great dram! Reasonably complex and incredibly well-balanced bit of</p>]]></description><link>https://blog.lukaspradel.com/highland-park-12/</link><guid isPermaLink="false">c58f8403-6360-49de-889e-bc075e30ac14</guid><category><![CDATA[Scotch]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Thu, 09 Apr 2015 06:45:30 GMT</pubDate><content:encoded><![CDATA[<p><strong>Highland Park 12</strong> <br>
<em>Island, 40%</em></p>

<p><strong>Nose</strong>: Pleasant earthiness. Heather. Some malt, hints of sherry.</p>

<p><strong>Colour:</strong> Dark gold.</p>

<p><strong>Taste:</strong> Some initial sherry. Very smooth. Heather-honey sweetness. Pineapple. Ever so gentle smoke. Delicious.</p>

<p><strong>Finish:</strong> Medium. Glorious Highland Park peat. Very dry.</p>

<p><strong>Summary:</strong> A great dram! Reasonably complex and incredibly well-balanced bit of everything. The HP smoke is extraordinary!</p>

<p><strong>Score:</strong> 88/100.</p>]]></content:encoded></item><item><title><![CDATA[Continuous integration for CMake projects using Travis CI]]></title><description><![CDATA[<p>Travis currently supports the following tools for building C++ projects according to their <a href="http://docs.travis-ci.com/user/languages/cpp/">official documentation</a>:</p>

<ul>
<li>gcc</li>
<li>clang</li>
<li>autotools</li>
<li>make</li>
<li>cmake</li>
<li>scons</li>
</ul>

<p>Using these is very straight forward. An example <code>.travis.yml</code> file for CMake projects looks like this:</p>

<pre><code>language: cpp

compiler:  
    - gcc
    - clang

before_script:  
    - mkdir build</code></pre>]]></description><link>https://blog.lukaspradel.com/continuous-integration-for-cmake-projects-using-travis-ci/</link><guid isPermaLink="false">d80a3b1e-f93e-4aee-bb41-d78f354cd0ea</guid><category><![CDATA[Continuous Integration]]></category><category><![CDATA[C++]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Thu, 15 Jan 2015 11:27:34 GMT</pubDate><content:encoded><![CDATA[<p>Travis currently supports the following tools for building C++ projects according to their <a href="http://docs.travis-ci.com/user/languages/cpp/">official documentation</a>:</p>

<ul>
<li>gcc</li>
<li>clang</li>
<li>autotools</li>
<li>make</li>
<li>cmake</li>
<li>scons</li>
</ul>

<p>Using these is very straight forward. An example <code>.travis.yml</code> file for CMake projects looks like this:</p>

<pre><code>language: cpp

compiler:  
    - gcc
    - clang

before_script:  
    - mkdir build
    - cd build
    - cmake ..

script: make  
</code></pre>

<p>We specify C++ as our language compiling with both gcc and clang. We create the standard CMake build directory and execute the cmake command in our project's home directory. Finally, we invoke make on the auto-generated Makefiles.</p>

<p>Using scons actually looks very similar to this: we just omit the cmake invocation and replace the script line with the following:</p>

<pre><code>script: scons  
</code></pre>]]></content:encoded></item><item><title><![CDATA[MBeans in Tomcat]]></title><description><![CDATA[<p>MBeans are part of the JMX specification which has been part of J2SE since Java 5. As such, Tomcat like most other servlet containers supports MBeans since version 5.</p>

<h4 id="configuringtomcat">Configuring Tomcat</h4>

<p>In order to access MBeans remotely, some configuration<sup><a href="https://blog.lukaspradel.com/mbeans-in-tomcat/#fn1" id="ref1">[1]</a></sup> is required. Tomcat provides a number of system arguments that</p>]]></description><link>https://blog.lukaspradel.com/mbeans-in-tomcat/</link><guid isPermaLink="false">9eb9a8c5-e3d6-45e8-abc9-7880dd0d5339</guid><category><![CDATA[Java]]></category><category><![CDATA[JMX]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Wed, 10 Dec 2014 13:01:31 GMT</pubDate><content:encoded><![CDATA[<p>MBeans are part of the JMX specification which has been part of J2SE since Java 5. As such, Tomcat like most other servlet containers supports MBeans since version 5.</p>

<h4 id="configuringtomcat">Configuring Tomcat</h4>

<p>In order to access MBeans remotely, some configuration<sup><a href="https://blog.lukaspradel.com/mbeans-in-tomcat/#fn1" id="ref1">[1]</a></sup> is required. Tomcat provides a number of system arguments that can be used to enable remote JMX access. As with all Tomcat configuration, the following is best placed in <code>$TOMCAT_ROOT/bin/setenv.sh</code>:</p>

<pre><code class="language-markup">-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=%YOUR_JMX_PORT% 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false
</code></pre>

<p>This allows anyone to remotely connect to your Tomcat's MBeans.</p>

<p>If you require secured access, consider the following:</p>

<pre><code class="language-markup">-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=%YOUR_JMX_PORT% 
-Dcom.sun.management.jmxremote.authenticate=true 
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=%IP address whitelist%
-Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password
-Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access
</code></pre>

<p>User access is managed in <code>$TOMCAT_ROOT/conf/jmxremote.access</code>:  </p>

<pre><code class="language-markup">monitorRole readonly  
controlRole readwrite  
</code></pre>

<p>And finally, the passwords are stored in <code>$TOMCAT_ROOT/conf/jmxremote.password</code>:  </p>

<pre><code class="language-markup">monitorRole tomcat-jmx-pw  
controlRole tomcat-jmx-pw2  
</code></pre>

<h4 id="registeringmbeans">Registering MBeans</h4>

<p>The easiest way of registering and unregistering your MBeans is by using a dedicated ServletContextListener whose sole purpose is to take care of your MBeans:</p>

<pre><code class="language-java">package com.lukaspradel.example.servlet;

import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;

import javax.management.InstanceAlreadyExistsException;  
import javax.management.InstanceNotFoundException;  
import javax.management.MBeanRegistrationException;  
import javax.management.MBeanServer;  
import javax.management.MalformedObjectNameException;  
import javax.management.NotCompliantMBeanException;  
import javax.management.ObjectName;  
import javax.servlet.ServletContext;  
import javax.servlet.ServletContextEvent;  
import javax.servlet.ServletContextListener;  
import javax.servlet.annotation.WebListener;

import java.lang.management.ManagementFactory;

@WebListener
public class MBeanContextListener implements ServletContextListener {

    private static final Logger LOG = LoggerFactory.getLogger(MBeanContextListener.class);

    private ObjectName exampleManagementObjectName;

    @Override
    public void contextInitialized(final ServletContextEvent sce) {

        LOG.debug("Register MBeans..");

        final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();

        try {
            exampleManagementObjectName = new ObjectName("com.lukaspradel.example.management:type=ExampleManagement");
            final ExampleManagement examleMbean = new ExampleManagement();
            mbeanServer.registerMBean(examleMbean, exampleManagementObjectName);
        } catch (InstanceAlreadyExistsException | MalformedObjectNameException | MBeanRegistrationException | NotCompliantMBeanException e) {
            LOG.error("Failed to register MBeans!", e);
        }
    }

    @Override
    public void contextDestroyed(final ServletContextEvent sce) {

        LOG.debug("Unregister MBeans..");

        final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();

        try {
            mbeanServer.unregisterMBean(exampleManagementObjectName);
        } catch (MBeanRegistrationException | InstanceNotFoundException e) {
            LOG.error("Failed to unregister MBeans!", e);
        }
    }
}
</code></pre>

<p>The callback functions defined by <code>ServletContextListener</code> provide excellent access points for registering and unregistering our MBeans. The boilerplate for the actual MBean handling is plain JMX and very straight-forward.</p>

<h4 id="callingmbeans">Calling MBeans</h4>

<p>A central MBeanInvoker will serve for demonstration purposes on how to remotely invoke MBean methods.</p>

<pre><code class="language-java">package com.lukaspradel.example.management;

import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;

import javax.enterprise.context.ApplicationScoped;  
import javax.management.JMX;  
import javax.management.MBeanServerConnection;  
import javax.management.ObjectName;  
import javax.management.remote.JMXConnector;  
import javax.management.remote.JMXConnectorFactory;  
import javax.management.remote.JMXServiceURL;

@ApplicationScoped
public class MBeanInvoker {

    private static final Logger LOG = LoggerFactory.getLogger(MBeanInvoker.class);

    private static final String JMX_URL = "service:jmx:rmi:///jndi/rmi://localhost:9012/jmxrmi";

    private static final String MBEAN_EXAMPLE_MANAGEMENT = "com.lukaspradel.example.management:type=ExampleManagement";

    private MBeanServerConnection mbsc;

    @PostConstruct
    public void init() {

        try {
            JMXServiceURL url = new JMXServiceURL(JMX_URL);
            JMXConnector jmxc = JMXConnectorFactory.connect(url, null);

            mbsc = jmxc.getMBeanServerConnection();
        } catch (Exception e) {
            LOG.error("Failed to initialize MBeanInvoker!", e);
        }
    }

    public String invokeExampleMBeanExampleMethod(String arg1) throws Exception {

        ObjectName exampleMBeanName = new ObjectName(MBEAN_SESSION_MANAGEMENT);
        ExampleManagementMBean exampleManagementMBean = JMX.newMXBeanProxy(mbsc, exampleMBeanName, ExampleManagementMBean.class, true);

        // not type-safe method
        // Object result = mbsc.invoke(exampleMBeanName, "exampleMethod", new Object[] {arg1}, new String[] {"java.lang.String"});

        String result = exampleManagementMBean.exampleMethod(arg1);

        return result;
    }
}
</code></pre>

<p>Again, the code is very straight-forward and self-explaining. We use plain JMX to create an <code>MBeanServerConnection</code> to our correctly configured Tomcat running as <code>localhost</code> at JMX port <code>9012</code>. What makes JMX truly great is that we can invoke the remote MBeans type-safe using their interfaces. Alternatively, reflection-esque method calling is also supported.</p>

<h4 id="finalremarks">Final remarks</h4>

<p>You can manually invoke your MBean methods for testing purposes using the J2SE tool <code>jconsole</code>. Connect to your Tomcat's JMX port by choosing "Remote process" and entering for example <code>localhost:9012</code>. Aside from the tab "MBeans" where you can manually invoke methods with arguments, you will also see other monitoring information like memory usage, Thread info and a JVM summary.</p>

<p><sup id="fn1">1. <a href="http://tomcat.apache.org/tomcat-7.0-doc/monitoring.html">http://tomcat.apache.org/tomcat-7.0-doc/monitoring.html</a><a href="https://blog.lukaspradel.com/mbeans-in-tomcat/#ref1">↩</a></sup></p>]]></content:encoded></item><item><title><![CDATA[Integration testing with the Maven Cargo plugin]]></title><description><![CDATA[<p>Testing user interfaces and successful deployment of web applications is a form of integration testing. In order to perform these tests it is necessary to automatically deploy your web application (WAR, EAR, ..) and its configuration artifacts (external properties, system arguments, ..) to some servlet container. One way of achieving this is</p>]]></description><link>https://blog.lukaspradel.com/integration-testing-with-the-maven-cargo-plugin/</link><guid isPermaLink="false">846b7c44-719d-464a-aa54-76bd9ce604b9</guid><category><![CDATA[Java]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Wed, 12 Nov 2014 12:43:49 GMT</pubDate><content:encoded><![CDATA[<p>Testing user interfaces and successful deployment of web applications is a form of integration testing. In order to perform these tests it is necessary to automatically deploy your web application (WAR, EAR, ..) and its configuration artifacts (external properties, system arguments, ..) to some servlet container. One way of achieving this is by performing continuous delivery to a dedicated testing or staging environment.</p>

<p>In this article I will demonstrate an alternative technique which involves integration testing as part of your build pipeline using the Maven Cargo plugin <sup><a href="https://blog.lukaspradel.com/integration-testing-with-the-maven-cargo-plugin/#fn1" id="ref1">[1]</a></sup>. The idea is to hook into the integration-test phase of the Maven Failsafe plugin which is by Maven convention the gateway to integration testing in the Maven lifecycle.</p>

<p>The setting that will serve as an example is as follows: our web application is built to a single WAR artifact that is deployed to a Tomcat servlet container. It is configured by properties files in a configuration directory outside of the application context. The location of the configuration directory is supplied by passing a JVM argument to the Tomcat instance.</p>

<h3 id="integratingautomatedcontainerdeployment">Integrating automated container deployment</h3>

<p>We begin by adding a dedicated profile for integration testing purposes. This can be useful to control when to perform integration tests as they tend to consume a lot more time than smoke tests or unit tests.</p>

<pre><code class="language-markup">    &lt;profiles&gt;
        &lt;profile&gt;
            &lt;id&gt;integration-test&lt;/id&gt;
            &lt;activation&gt;
                &lt;activeByDefault&gt;true&lt;/activeByDefault&gt;
            &lt;/activation&gt;
            &lt;build&gt;
                &lt;plugins&gt;
                    &lt;plugin&gt;
                        &lt;artifactId&gt;maven-failsafe-plugin&lt;/artifactId&gt;
                    &lt;/plugin&gt;
                    &lt;plugin&gt;
                        &lt;groupId&gt;org.codehaus.cargo&lt;/groupId&gt;
                        &lt;artifactId&gt;cargo-maven2-plugin&lt;/artifactId&gt;
                        &lt;version&gt;${cargo.plugin.version}&lt;/version&gt;
                        &lt;configuration&gt;
                            &lt;container&gt;
                                &lt;containerId&gt;tomcat7x&lt;/containerId&gt;
                                &lt;zipUrlInstaller&gt;
                                    &lt;url&gt;http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.54/bin/apache-tomcat-7.0.54.zip&lt;/url&gt;
                                    &lt;downloadDir&gt;${project.build.directory}/downloads&lt;/downloadDir&gt;
                                    &lt;extractDir&gt;${project.build.directory}/extracts&lt;/extractDir&gt;
                                &lt;/zipUrlInstaller&gt;
                            &lt;/container&gt;
                            &lt;deployables&gt;
                                &lt;deployable&gt;
                                    &lt;properties&gt;
                                        &lt;context&gt;ROOT&lt;/context&gt;
                                    &lt;/properties&gt;
                                &lt;/deployable&gt;
                            &lt;/deployables&gt;
                            &lt;configuration&gt;
                                &lt;configfiles&gt;
                                    &lt;configfile&gt;
                                        &lt;file&gt;${cargo.container.configuration.src.dir}/config1.properties&lt;/file&gt;
                                        &lt;todir&gt;${cargo.container.configuration.to.dir}&lt;/todir&gt;
                                    &lt;/configfile&gt;
                                    &lt;configfile&gt;
                                        &lt;file&gt;${cargo.container.configuration.src.dir}/config2.properties&lt;/file&gt;
                                        &lt;todir&gt;${cargo.container.configuration.to.dir}&lt;/todir&gt;
                                    &lt;/configfile&gt;
                                &lt;/configfiles&gt;
                            &lt;/configuration&gt;
                        &lt;/configuration&gt;
                        &lt;executions&gt;
                            &lt;execution&gt;
                                &lt;id&gt;start-tomcat&lt;/id&gt;
                                &lt;phase&gt;pre-integration-test&lt;/phase&gt;
                                &lt;goals&gt;
                                    &lt;goal&gt;start&lt;/goal&gt;
                                &lt;/goals&gt;
                                &lt;configuration&gt;
                                    &lt;configuration&gt;
                                        &lt;properties&gt;
                                            &lt;cargo.jvmargs&gt;${cargo.container.jvmargs}&lt;/cargo.jvmargs&gt;
                                        &lt;/properties&gt;
                                    &lt;/configuration&gt;
                                &lt;/configuration&gt;
                            &lt;/execution&gt;
                            &lt;execution&gt;
                                &lt;id&gt;stop-tomcat&lt;/id&gt;
                                &lt;phase&gt;post-integration-test&lt;/phase&gt;
                                &lt;goals&gt;
                                    &lt;goal&gt;stop&lt;/goal&gt;
                                &lt;/goals&gt;
                            &lt;/execution&gt;
                        &lt;/executions&gt;
                    &lt;/plugin&gt;
                &lt;/plugins&gt;
            &lt;/build&gt;
        &lt;/profile&gt;
    &lt;/profiles&gt;
</code></pre>

<p>We begin by configuring the Maven Failsafe plugin and further use the Cargo plugin whose executions we bind to the <code>pre-integration-test</code> and <code>post-integration-test</code> phases respectively. The idea is to start the Tomcat during <code>pre-integration-test</code> and deploy our application and to gracefully shutdown the Tomcat during <code>post-integration-test</code>.</p>

<p>Firstly, we configure one or more containers. In this case we need only a Tomcat which we download directly from the Apache archive to <code>target/downloads</code> and extract it to <code>target/extracts</code>. Our deployable WAR artifact is deployed as ROOT in this example. The <code>configfiles</code> property is used to manually copy external artifacts into the application context. Finally, we can configure JVM arguments in the <code>pre-integration-test</code> phase by configuring the <code>cargo.jvmargs</code> property.</p>

<p>For reference, the properties section of our POM looks like this:  </p>

<pre><code class="language-markup">&lt;properties&gt;  
...
        &lt;cargo.plugin.version&gt;1.4.9&lt;/cargo.plugin.version&gt;
        &lt;cargo.container.configuration.src.dir&gt;${basedir}/../configuration-test/src/main/resources/com/lukaspradel/example/configuration/test&lt;/cargo.container.configuration.src.dir&gt;
        &lt;cargo.container.configuration.to.dir&gt;conf/properties/test&lt;/cargo.container.configuration.to.dir&gt;
        &lt;cargo.container.jvmargs&gt;-D.configuration.dir=${cargo.container.configuration.to.dir}
            -Dcom.sun.management.jmxremote
            -Dcom.sun.management.jmxremote.port=9012
            -Dcom.sun.management.jmxremote.authenticate=false
            -Dcom.sun.management.jmxremote.ssl=false&lt;/cargo.container.jvmargs&gt;
...
&lt;/properties&gt;  
</code></pre>

<p>This integrates automatic setup of a container as well as deployment of our application to said container into our build pipeline. A list of supported containers can be found in the documentation of the Cargo plugin. All common containers are supported such as</p>

<ul>
<li>Geronimo</li>
<li>Glassfish</li>
<li>JBoss</li>
<li>Jetty</li>
<li>Tomcat</li>
<li>WebLogic</li>
<li>WebSphere</li>
<li>Wildfly</li>
</ul>

<p>Take a look at the official doc <sup><a href="https://blog.lukaspradel.com/integration-testing-with-the-maven-cargo-plugin/#fn2" id="ref2">[2]</a></sup>.</p>

<h3 id="basicsmoketesting">Basic smoke testing</h3>

<p>By convention, all unit test classes whose names end with <code>IT</code> are considered integration tests by the Maven failsafe plugin. Hence, no further configuration is necessary, unless you wish to differentiate them further.</p>

<p>As a basic integration smoke test we will check if our application is deployed successfully and the Tomcat serves with HTTP code OK (200). An easy to use HTTPClient is the Apache httpclient:</p>

<pre><code class="language-markup">&lt;dependencies&gt;  
...
        &lt;dependency&gt;
            &lt;groupId&gt;org.apache.httpcomponents&lt;/groupId&gt;
            &lt;artifactId&gt;httpclient&lt;/artifactId&gt;
            &lt;version&gt;${httpclient.version}&lt;/version&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
...
&lt;/dependencies&gt;  
</code></pre>

<p>Our smoke test looks as follows:  </p>

<pre><code class="language-java```">package com.lukaspradel.example.it;

import com.lukaspradel.example.it.common.AbstractIntegrationTest;  
import org.apache.http.HttpResponse;  
import org.apache.http.HttpStatus;  
import org.apache.http.client.ClientProtocolException;  
import org.apache.http.client.CookieStore;  
import org.apache.http.client.HttpClient;  
import org.apache.http.client.methods.HttpGet;  
import org.apache.http.client.protocol.HttpClientContext;  
import org.apache.http.impl.client.BasicCookieStore;  
import org.apache.http.impl.client.HttpClientBuilder;  
import org.testng.annotations.Test;

import java.io.IOException;

import static org.testng.Assert.assertEquals;

/**
 * Check if the application was deployed correctly during integration-test phase
 * and if it can be reached successfully.
 *
 * @author pradel
 *
 */
public class CheckApplicationDeploymentIT extends AbstractIntegrationTest {

    @Test
    public void testWebapplicationUp() throws ClientProtocolException, IOException {

        HttpClient client = HttpClientBuilder.create().build();
        CookieStore cookieStore = new BasicCookieStore();
        HttpClientContext context = HttpClientContext.create();
        context.setCookieStore(cookieStore);

        HttpGet httpget = new HttpGet(BASE_URL);

        HttpResponse response = client.execute(httpget, context);

        assertEquals(response.getStatusLine().getStatusCode(), HttpStatus.SC_OK);
    }
}
</code></pre>

<p>Here, we assume that <code>AbstractIntegrationTest</code> supplies something like <br>
<code>protected static final String BASE_URL = "http://localhost/";</code>.</p>

<p><sup id="fn1">1. <a href="http://cargo.codehaus.org/Home">http://cargo.codehaus.org/Home</a><a href="https://blog.lukaspradel.com/integration-testing-with-the-maven-cargo-plugin/#ref1">↩</a></sup> <br>
<sup id="fn2">2. <a href="http://cargo.codehaus.org/Containers">http://cargo.codehaus.org/Containers</a><a href="https://blog.lukaspradel.com/integration-testing-with-the-maven-cargo-plugin/#ref2">↩</a></sup></p>]]></content:encoded></item><item><title><![CDATA[Review: Glen Deveron 10]]></title><description><![CDATA[<p><strong>Glen Deveron 10</strong> <br>
<em>Speyside, 40%</em></p>

<p><strong>Nose</strong>: Very dominant malt. Strong toffee. Some citrus. A bit of sweetness yet kind of alcoholic.</p>

<p><strong>Colour:</strong> Darker amber.</p>

<p><strong>Taste:</strong> Oily body. Very malty. Lots of toffee. Some dark fruits. A distinct touch of oak. Hints of lemons.</p>

<p><strong>Finish:</strong> Very short. Dangerously quaffable. A bit</p>]]></description><link>https://blog.lukaspradel.com/review-glen-deveron-10/</link><guid isPermaLink="false">4b13c292-f7f0-4165-8233-53ff7e2de85e</guid><category><![CDATA[Scotch]]></category><dc:creator><![CDATA[Lukas]]></dc:creator><pubDate>Wed, 08 Oct 2014 13:00:59 GMT</pubDate><content:encoded><![CDATA[<p><strong>Glen Deveron 10</strong> <br>
<em>Speyside, 40%</em></p>

<p><strong>Nose</strong>: Very dominant malt. Strong toffee. Some citrus. A bit of sweetness yet kind of alcoholic.</p>

<p><strong>Colour:</strong> Darker amber.</p>

<p><strong>Taste:</strong> Oily body. Very malty. Lots of toffee. Some dark fruits. A distinct touch of oak. Hints of lemons.</p>

<p><strong>Finish:</strong> Very short. Dangerously quaffable. A bit woody. Surprisingly bitter. Leaves a bitter taste of tobacco after a few minutes.</p>

<p><strong>Summary:</strong> An average dram. By no means bad but certainly not exceptional either. A good deal for the very low price.</p>

<p><strong>Score:</strong> 73/100.</p>]]></content:encoded></item></channel></rss>