Watching a Directory for Changes

Watch Service Overview

The WatchService API is fairly low level, allowing you to customise it. You can use it as is, or you can choose to create a high-level API on top of this mechanism so that it is suited to your particular needs. The WatchService API lets you receive notification events upon changes to the subject (directory or file).

The steps involved in implementing the API are:

  • Create a WatchService. This service consists of a queue to holdWatchKeys
  • Register the directory/file you wish to monitor with this WatchService
  • While registering, specify the types of events you wish to receive (create, modify or delete events)
  • You have to start an infinite loop to listen to events
  • When an event occurs, a WatchKey is placed into the queue
  • Consume the WatchKey and invoke queries on it

Let’s follow this via an example. We create a DirWatcher Java program whose responsibility is to watch a particular directory (Downloads in my case). The steps are provided below:

1. Creating an WatchService object:

2. Obtain a path reference to your watchable directory. I suggest you parameterize this directory so you don’t hard code the file name.

3. The next step is to register the directory with the WatchService for all types of events:

When registering an object with the watch service, you specify the types of events that you want to monitor. The supported StandardWatchEventKinds event types follow:

  • ENTRY_CREATE – A directory entry is created.
  • ENTRY_DELETE – A directory entry is deleted.
  • ENTRY_MODIFY – A directory entry is modified.
  • OVERFLOW – Indicates those events might have been lost or discarded. You do not have to register for the OVERFLOW event to receive it.

4. Initiate the infinite loop and start taking the events:

 

5. Run through the events on the key:

For example, if you modify or delete the Download directory, you would see statement as shown below on the console respectively:

 

Example source code:

 

 

Simple Jersey example with Intellij IDEA Ultimate and Tomcat

Jersey

RESTful Web Services in Java.

Jersey is a reference implementation of the JAX-RS 2.0 API. Jersey provides it’s own API that extends the JAX-RS toolkit with additional features and utilities to further simplify RESTful service and client development.

In this example I will be using:

  • IntelliJ Idea Ultimate 2016.2
  • Jersey 2.23.2 (latest stable release of Jersey as of time of writing)
  • JDK 8
  • Tomcat 8.0.35

Create new project

To create a new project, open up the New Project dialog in IntelliJ. In the left menu, select Java Enterprise. To the right, select Web Application and ensure that Create web.xml is checked.

newproject

 

Add Maven support

To add Maven to your project, right-click on your project’s name in the Project sidebar and select Add Framework Support.

In the Add Frameworks Support, select Maven.

Once this is done, the pom.xml file will open in the editor. You will need to enter at least a groupId, usually your package name. At this point, it is helpful to enable auto-importing for library dependencies.

maven

Add Jersey dependencies to the Maven pom.xml file

 

Create a Resource

Inside of the src/main/java directory, create a new package matching your groupId.

And then create a simple java class – MyResource in my case.

Modify index.jsp file by adding a link to the Jersey resource

 

Check if Tomcat is configured properly.

tomcat-configuration

tomcat-deployment

 

Configure your servlet

Modify your web.xml file

 

Before we run our application, first we need to add Jersey jars to the /WEB-INF/lib directory

add-artifacts

After selecting all jars right click and choose “Put into /WEB-INF/lib

Run your Application

jersey-resource
got-it

 

DONE!

 

 

Git for an absolute beginners

Before I started using Git on my personal and then on commercial projects, I was using for many years  Subversion – svn in short. SVN is still very popular but Git earned its strong position as well by being used in large and small projects for more than 10 years already.

Installing Git

The official website of Git has detailed information about installing on Linux, Mac, or Windows. In this case, I will be using Ubuntu 16.04 for demonstration purposes, and installing git in Linux (Ubuntu) is simple as typing:

Before we dive into configuration and will start using Git a bit of terminology introduction is necessary.

Here’s the git terminology:

  • master – the repository’s main branch. Depending on the workflow it is the one people work on or the one where the integration happens
  • clone – copies an existing git repository, normally from some remote location to your local environment.
  • commit – submitting files to the repository (the local one); in other VCS it is often referred to as “checkin”
  • fetch or pull – is like “update” or “get latest” in other VCS. The difference between fetch and pull is that pull combines both, fetching the latest code from a remote repo as well as performs the merging.
  • push – is used to submit the code to a remote repository
  • remote – these are “remote” locations of your repository, normally on some central server.
  • SHA – every commit or node in the Git tree is identified by a unique SHA key. You can use them in various commands in order to manipulate a specific node.
  • head – is a reference to the node to which our working space of the repository currently points.
  • branch – is just like in other VCS with the difference that a branch in Git is actually nothing more special than a particular label on a given node. It is not a physical copy of the files as in other popular VCS.

Initial Configuration

We need to configure our name and email. You can do it as follows, replacing the values with your own name and email.

It is important to note that if you do not set your name and email, certain default values will be used.

Create a new Git Repository

Before starting, let’s create a new directory where the git repository will be created and ‘move’ into it.

Now we can initialize our first git repository.

To check the status of our repository git status command can be used.

Create and commit a new file

The next step is to create a new file and add some content to it.

Let’s check what happen in our git repository.

To “register” the file for committing we need to add it to git using:

And again, let’s check what happen in our git repository.

 

We can now commit it to the repository.

Let’s add another file to the project.

 

Create a (feature) branch

Branching and merging is what makes Git so powerful and for what it has been optimised, being a distributed version control system (VCS). Indeed, feature branches are quite popular to be used with Git. Feature branches are created for every new kind of functionality you’re going to add to your system and they have usually deleted afterwards once the feature is merged back into the main integration branch (normally the master branch). The advantage is that you can experiment with new functionality in a separate, isolated “playground” and quickly switch back and forth to the original “master” branch when needed. Moreover, it can be easily discarded again (in case it is not needed) by simply dropping the feature branch. But let’s get started and create the new feature branch:

To see a list of all branches we need to use git branch command.

A star next to master branch indicates that this is a current branch.

Let’s switch to this newly created branch and modify one of the files.

And then add and commit it to the branch.

 

Ok, it’s time to complicate it and cause some conflicts. To do this we need to switch to ‘master’ branch and modify the blogpost.txt file.

 

If you need to commit a file that was already added to the git repository you can use command ‘commit -a -m’

Merge and resolve conflicts

The next step would be to merge our feature branch back into ‘master’. This is done by using the merge command.

Edit file and resolve conflict and commit changes to the branch.

 

Rollback

What if we want to undo everything back to the state before the commit?

First, we need to get SHA identifiers (unique ‘id’ for each node in git tree).

 

and then move back in time to the desired node/commit

 

 

And that’s it. It is everything that is needed to start using git. I have covered here only simple commands. For more advanced commands and explanations I highly recommend reading this book: Pro GIT.

JUnit – assertThat (Hamcrest) – part 3

Ok, it’s time to continue our series of examples Hamcrest matchers usage. Previous blog posts can be found here (part 1part 2).

  • endsWith()

Creates a matcher that matches if the examined String ends with the specified String.

 

  • equalTo()

Creates a matcher that matches when the examined object is logically equal to the examined object.

 

equalTo() can also be used on Arrays in which case it will check the length of the Array and ensure that all the values in the input test array are logically equal to the values of the specified array.

 

  • equalToIgnoringCase()

Creates a matcher of String that matches when the examined string is equal to the specified expectedString, ignoring case.

 

  • equalToIgnoringWhiteSpace()

Creates a matcher of String that matches when the examined string is equal to the specified expected String when whitespace differences are (mostly) ignored. To be exact, the following whitespace rules are applied:

  1. all leading and trailing whitespace of both the expected String and the examined string are ignored
  2. any remaining whitespace, appearing within either string, is collapsed to a single space before comparison

 

  • greaterThan()

Creates a matcher of Comparable object that matches when the examined object is greater than the specified value, as reported by the compareTo method of the examined object.

 

  • greaterThanOrEqualTo()

Creates a matcher of Comparable object that matches when the examined object is greater than or equal to the specified value, as reported by the compareTo method of the examined object.

 

  • hasEntry()

Creates a matcher for Maps matching when the examined Map contains at least one entry whose key equals the specified key and whose value equals the specified value.

 

  • hasKey()

Creates a matcher for Maps matching when the examined Map contains at least one key that satisfies the specified matcher.

 

  • hasValue()

Creates a matcher for Maps matching when the examined Map contains at least one value that is equal to the specified value.

 

  • hasItem()

Creates a matcher for Iterables that only matches when a single pass over the examined Iterable yields at least one item that is equal to the specified item. Whilst matching, the traversal of the examined Iterable will stop as soon as a matching item is found.

 

  • hasItems()

Creates a matcher for Iterables that matches when consecutive passes over the examined Iterable yield at least one item that is equal to the corresponding item from the specified items. Whilst matching, each traversal of the examined Iterable will stop as soon as a matching item is found.

 

  • hasSize()

Creates a matcher for Collections that matches when the size() method returns a value equal to the specified size.

 

  • instanceOf()

Creates a matcher that matches when the examined object is an instance of the specified type.