February 03, 2017

Simple Windows mirror directory backup with robocopy

Quick Tip

This is a simple Visual Basic script (Listing 1) that uses the windows robocoy command to perform a simple mirroring backup of a directory structure. Typically, use this to backup from your local machine to a network location just in case something happens to your hard drive.

NOTE This is a simple MIRROR copy backup strategy. There is no history maintained. If it’s obliterated during the backup, it’s gone!

Listing 1 - Single Statement File to String

Set WshShell = WScript.CreateObject ("WScript.Shell")
Return = WshShell.Run("cmd.exe /C robocopy C:\source X:\destination /MIR", 1)

January 18, 2017

Jacoco, Surefire & Argline: Why jacoco.exe isn't created

Abstract

Are you using Jacoco to give you statistics on the unit test coverage of your source code? Have you encountered a problem where jacoco.exe is not created by jacoco-maven-plugin?. Then keep reading, I’ve got your answer.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Requirements

I did all of the work for this post using the following major technologies. You may be able to do the same thing with different technologies or versions, but no guarantees.

  • Java 1.8.0_65_x64
  • jacoco-maven-plugin 0.7.5.201505241946
  • maven-surefire-plugin 2.17
  • Maven 3.0.5 (Bundled with NetBeans)

Where are your tests?

Does your project even have unit tests? You sure? Take a look! If your project doesn’t have any unit tests, then jacoco.exe is not created. I’m sure your project already has unit tests, but, it’s always good to check that the lamp is plugged in first :). Now let’s get to a more interesting reason why jacoco.exe is not being created: <argLine>.

Watch out for <argLine>

If you have been using Jacoco and suddenly the jacoco.exe is not created, then chances are you have an <argLine> problem. Jacoco connects itself to the surefire plugin by editing the <argLine> value of that plugin. If you don’t set <argLine> then you’re fine. But if you do, you’ll mess up Jacoco if you don’t do it properly.

Let’s take a look at how NOT to do it. The <properties> tag is typically used to configure plugins and Listing 1 shows you what NOT to do.

Listing 1 - Don’t use <properties> to configure plugins

<properties>
  <!-- Do not configure plugin with properties -->
  <surefire.plugin.argline>-XX:PermSize=256m -XX:MaxPermSize=1048m</surefire.plugin.argline>
</properties>

Instead, configure <argLine> in the plugin itself, and include in the configuration the assumption that Jacoco has already set the <argLine> value. Listing 2 shows how to properly configure Surefire.

Listing 2 - Prepend Jacoco’s argLine value to your value

<build>
  <plugins>
      ...
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
           <argLine>${argLine} -XX:PermSize=256m -XX:MaxPermSize=1048m</argLine>
         </configuration>
      </plugin>
      ...
  </plugins>
</build>

This may look a little funny - <argLine>${argLine} -XX:PermSize=256m -XX:MaxPermSize=1048m</argLine> - but this is really nothing more than string concatenation. The Jacoco plugin automatically sets the value argLine. So if you need to set its value too, you use a standard variable reference to ${argLine} to prepend Jacoco’s value to your value. Finally, Listing 3 shows a very basic jacoco-maven-plugin configuration.

Listing 3 - Very basic Jacoco configuration

<build>
  <plugins>
    ...
    <plugin>
      <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
      <version>0.7.5.201505241946</version>
      <configuration>
        <excludes>
          <exclude>org/company/*</exclude>
        </excludes>
      </configuration>
      <executions>
        <execution>
          <id>default-prepare-agent</id>
          <phase>initialize</phase>
          <goals>
            <goal>prepare-agent</goal>
          </goals>
        </execution>
        <execution>
          <id>default-check</id>
          <phase>verify</phase>
          <goals>
            <goal>check</goal>
          </goals>
          <configuration>
            <rules>
              <rule implementation="org.jacoco.maven.RuleConfiguration">
                <element>BUNDLE</element>
                <limits>
                  <limit implementation="org.jacoco.report.check.Limit">
                    <counter>INSTRUCTION</counter>
                    <value>COVEREDRATIO</value>
                    <minimum>0.0</minimum>
                  </limit>
                  <limit implementation="org.jacoco.report.check.Limit">
                    <counter>BRANCH</counter>
                    <value>COVEREDRATIO</value>
                    <minimum>0.0</minimum>
                  </limit>
                  <limit implementation="org.jacoco.report.check.Limit">
                    <counter>CLASS</counter>
                    <value>MISSEDCOUNT</value>
                    <maximum>1000</maximum>
                  </limit>
                </limits>
              </rule>
            </rules>
          </configuration>
        </execution>
        <execution>
          <id>default-report</id>
          <phase>verify</phase>
          <goals>
            <goal>report</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
</build>

In listing 3, you can see the prepare-agent goal is configured to be executed at the initialize phase of the Maven life cycle. This goal is what sets the <argLine> value. Then, when the Surefire plugin runs, the jacoco.exe file gets created correctly and the unit test statistics are collected.

Summary

If jacoco.exe is not being created for you, the <argline> value is moste likely your problem. Remove any <properties> that set the argline value and configure <argLine> in the plugin itself. When you do so, remember to include Jacoco’s value by prepending the value like <argLine>${argLine} -XX:PermSize=256m -XX:MaxPermSize=1048m</argLine>.

References

Ryan Nelson. (2016, September 27). jacoco’s prepare-agent not generating jacoco.exec file [Web log comment]. Retrieved from http://stackoverflow.com/questions/21633277/jacocos-prepare-agent-not-generating-jacoco-exec-file.

Hoffmann, Marc R. (2013, October 3). jacoco.exec file is not generated after running jacoco maven ‘prepare-agent’ goal [Web log comment]. Retrieved from https://groups.google.com/forum/#!topic/jacoco/LzmCezW8VKA.

jacoco:prepare-agent. (n.d.). In EclEmma. Retrieved January 12, 2017, from http://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html.

September 23, 2016

CDI @Inject beans into @Path JAX-RS Resource

Abstract

Recently, I was doing some research into JAX-RS and ran into a problem. I attempted to use CDI to @Inject a bean into the JAX-RS resource. It failed miserably. Different attempts produced different failures. Sometimes exceptions occurred during deployment, other times exceptions occurred when invoking the JAX-RS endpoint. After much trial and error, and some asking on Stackoverflow, I found 2 solution. This post describes these 2 solutions to get CDI and JAX-RS working together.

Requirements

I did all of the work for this post using the following major technologies. You may be able to do the same thing with different technologies or versions, but no guarantees.

  • Java EE 7
  • Payara 4.1.1.161
  • Java 1.8.0_65_x64
  • NetBeans 8.1
  • Maven 3.0.5 (Bundled with NetBeans)

Downloads

All of the research & development work I did for this post is available on my GitHub account. Feel free to download or clone the thoth-jaxrs GitHub project.

Exceptions

As soon as I tried to use CDI to @Inject a bean into a JAX-RS @Path resource, my application ran into trouble. I tried resolving the trouble in a lot of different ways but I kept getting either deployment exceptions or runtime exceptions. For reference, here are the exceptions I was typically getting.

Deployment Exception

The deployment exception obviously happened at deployment time. When these happened, the application failed to deploy.

Exception during lifecycle processing
java.lang.Exception: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.apache.catalina.LifecycleException: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type InjectMe with qualifiers @Default at injection point [BackedAnnotatedField] @Inject private org.thoth.jaspic.web.InjectResource.me

Runtime Exception

The runtime exception happened when attempting to invoke the JAX-RS resource with a browser. For this exception, the application deployed without errors, but this one JAX-RS resource wasn’t working.

MultiException stack 1 of 1
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=InjectMe, parent=InjectResource, qualifiers={}, position=-1, optional=false, self=false, unqualified=null, 1000687916))

Resolution 1: beans.xml

This is the first resolution I found. The key factor was adding a beans.xml file to the web project and configuring beans.xml with bean-discovery-mode="all". This allows CDI to consider all classes for injection. This is not a preferred solution however. For reference, here are all the major files in the project.

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="all">
</beans>

JAX-RS Application Configuration

import javax.ws.rs.core.Application;

@javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {

}

JAX-RS Resource

import java.security.Principal;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.SecurityContext;

@Path("inject")
public class InjectResource {

    @Inject
    private InjectMe injectMe;

    @GET
    @Produces(MediaType.TEXT_HTML)
    public String getText(@Context SecurityContext context) {
        Principal p = context.getUserPrincipal();
        String retval = "";
        retval += "<!DOCTYPE html>\n";
        retval += "<h3>Thoth</h3>\n";
        retval += "<h4>jaxrs-inject</h4>\n";
        retval += String.format("<p>injectMe=[%s]</p>\n", injectMe);
        return retval;
    }
}

Simple bean to inject

import java.io.Serializable;

public class InjectMe implements Serializable {

    private static final long serialVersionUID = 158775545474L;

    private String foo;
    
    public String getFoo() {
        return foo;
    }
    public void setFoo(String foo) {
        this.foo = foo;
    }
}

Resolution 2: Scope Annotations

The second resolution - and the preferred solution - is to annotate the classes with scope annotations. The key factor here is to annotate both the JAX-RS @Path resource and the bean to inject with a scope annotation. This then works with the CDI default discovery mode which is ‘annotated’. Because both these classes are annotated with scope annotations, CDI will automatically discover them without the need for a beans.xml file. And this is important because we want to avoid having a beans.xml if possible and configure the application with only annotations. For reference, here are all the major files in the project. In this example, both are annotated with @RequestScope which makes them discoverable to CDI.

NOTE Thanks to “leet java” and “OndrejM” for responding to my Stackoverflow question. I mistakenly assumed the @Path annotation made a class discoverable by CDI and they pointed that out to me, thanks!.

JAX-RS Application Configuration

import javax.ws.rs.core.Application;

@javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {

}

JAX-RS Resource

import java.security.Principal;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.SecurityContext;

@Path("inject")
@RequestScoped
public class InjectResource {

    @Inject
    private InjectMe injectMe;

    @GET
    @Produces(MediaType.TEXT_HTML)
    public String getText(@Context SecurityContext context) {
        Principal p = context.getUserPrincipal();
        String retval = "";
        retval += "<!DOCTYPE html>\n";
        retval += "<h3>Thoth</h3>\n";
        retval += "<h4>jaxrs-inject-annotation</h4>\n";
        retval += String.format("<p>this=[%s]</p>\n", this);
        retval += String.format("<p>injectMe=[%s]</p>\n", injectMe);
        return retval;
    }
}

Simple bean to inject

import java.io.Serializable;
import javax.enterprise.context.RequestScoped;

@RequestScoped
public class InjectMe implements Serializable {

    private static final long serialVersionUID = 158775545474L;

    private String foo;

    public String getFoo() {
        return foo;
    }
    public void setFoo(String foo) {
        this.foo = foo;
    }
}

Summary

This problem and its eventual solution may seem trivial. However, when using tools (like NetBeans) to automatically generate your projects it’s easy to forget about things like annotations and beans.xml files since so much code is generated for you. So hopefully this will help you save some time if you run into this problem.

References

Remijan, M. (2016, September 22). Is bean-discovery-mode=“all” required to @Inject a bean into a Jersey @Path JAX-RS resource?. Retrieved from http://stackoverflow.com/questions/39648790/is-bean-discovery-mode-all-required-to-inject-a-bean-into-a-jersey-path-jax.

User2764975. (2015 September 18). CDI and Resource Injection with JAX-RS and Glassfish. Retrieved from http://stackoverflow.com/questions/32660066/cdi-and-resource-injection-with-jax-rs-and-glassfish.