Enhanced Navigation in Vaadin with NavigationBuilder

Developing your navigation needs in default Vaadin is ok, but I thought it could be enhanced a bit. Hence the idea of creating a new addon, NavigationBuilder.

The Idea Behind the Addon

In fact there where multiple reasons why I wanted to create some additional navigation functionality. Chaining calls to build navigation actions seemed just right. With such an approach you can achieve incredibly readable code, when properly formatted.

Besides the readability and the need to create navigation calls in a unified way, I thought that navigation actions often provide good events to trigger your own custom code. An event-handling implementation seemed suitable.

The general purpose was to make it all easier and more accessible. I also wanted to bundle refresh, back and next actions in the implementation, as they are simply navigation calls.

Builder Approach

It seemed fairly logical to apply a builder-pattern in the library. Let’s crack on with a quick example.

NavigationUtils.navigate()
                .to("www.google.com")
                .inNewTab()
                .withListener(event1 -> 
                 LOGGER.trace("Navigating to external url in a new tab."))
                .go();

With the above formatting, the chained calls are easy to read. The opening method NavigationUtils.navigate(); provides us with the Builder object from which we’ll always start. In the example above we specify an external destination url and we tell the builder that we’ll want to open the link in a new tab. After that, we attached a listener that executed our own custom code (in this case a simple log output line). Calling .go(); will build our navigation action and perform it right away. Straight forward, right?

In fact, many calls are optional and can simply be left out. The action can also be stored in a variable for later execution. That would look something like the next example.

NavigateExecutor navigation = NavigationUtils.navigate()
                .to("http://thibaulthelsmoortel.be")
                .build();
navigation.perform();

This way you can prepare all the required actions beforehand and just perform them whenever needed.

Reduced Boilerplate

At the moment of writing boilerplate code can be slightly reduced. The NavigationUtil class contains a few methods with very common navigation needs pre-configured.

Here are a few examples of how you could use those pre-built actions.

NavigationUtils.createReloadNavigation().withListener(l -> System.out.println("Page reloaded!")).go(); // Adding a listener to the pre-configured navigation.
NavigationUtils.createBackNavigation().go(); // Go back one page in the browser history
NavigationUtils.createNextNavigation().go(); // Go one page forward in the browser history

In fact, that pretty much sums it all up for now. If you have additional ideas for expanding the project, feel free to share them. I will respond to questions and feedback in comments.

If you are experiencing issues, please file them on GitHub. They will all be looked at.

The addon’s version at the time of writing is 1.1.2. Note that the addon will get updated every so often, so be aware of changes.

Interested in other Vaadin stuff? You might as well read my latest Vaadin related article about loading animations.

Managing Application Properties in Spring Boot

Many projects deal with application-wide parameters, mostly called properties. These are inputs to the program, that wouldn’t normally be changed. They do however provide for simple setup in multiple circumstances.

When to Use Properties

Good example situations in which properties would come in handy are database and email setups. If your application sends out mails, it will need to set some parameters, like protocol, host and port. If authentication is involved, properties should cover them as well. In your emailing implementation you would then read out the property values and handle them however required.

Mail properties
Some application properties for outgoing email for local development.

There are many advantages of setting these parameters in one centralized file. One of which is that quick adjustments can easily be made, without touching the code (that is, when only values are edited). When an application is deployed on multiple environments (local development, acceptance, staging, production,…) it would be enough to adjust properties in accordance with the environment on which the app is running on.

 

Reading Properties in Spring

When it comes down to extracting the values from the property file(s) when using Spring, you have a few options.

The first option, which is also the quickest solution, is to use the @Value annotation on class members or directly in an autowired constructor, as a parameters.

@Value("${my.property.name}")
private String myProperty;
@Autowired
 public MyConstructor(@Value("${my.property.name}") final String property) {
     this.property = property;
 }

Just pass your property key to the annotation. That’s it, no need to use any file reader, Spring deals with that for you. However this method is very quick and easy to implement, I’d like to point out that whenever you decide to edit the property key, you would also have to adjust it in the annotation value in code. And that would be for every annotation that reads out the edited property in question. This could obviously be made a bit more efficient and future proof.

Read Once, Access Anytime

A more solid approach would be to read all the properties (ideally when the application is launched) and put them into memory, so they would be accessible throughout the entire lifecycle of the program. Spring makes this incredibly easy, so this is by far the recommended approach.

Example class with properties in memory.
Example class with properties in memory.

In the image above, you can see an example of a class containing application properties. It contains no business logic whatsoever. The class must be annotated with Spring’s @ConfigurationProperties annotation. You can pass a prefix value (the prefix of the property key) if so required. The nested classes cover the nested properties. The protocol property in the Mail class would be the described as cs.mail.protocol in the properties file in this case. If a property key requires editing in the future, only the key and its respective property should be adjusted in code, never more, never less.

The @Data annotation (Lombok) generates all the necessary getters and setters and it reduces boilerplate code at the same time (oh, and it makes you develop that little bit faster). You could of course provide the getters and setters yourself if you don’t want to use Lombok.

Additional Spring Configuration

Not much more left to do in order to make the properties accessible in any spring component. To follow the previous example, I’d like to bring in an example Spring configuration class:

@Configuration
@EnableConfigurationProperties({ CSProperties.class })
public class PropertiesConfig {

    private final CSProperties properties;

    @Autowired public PropertiesConfig(CSProperties properties) {
        this.properties = properties;
    }

    @Bean
    public CSProperties.Database getDatabase() {
        return properties.getDb();
    }

    @Bean
    public CSProperties.Mail getMail() {
        return properties.getMail();
    }

    @Bean
    public CSProperties.Background getBackground() {
        return properties.getBackground();
    }

    @Bean
    public CSProperties.Cache getCache() {
        return properties.getCache();
    }

What this class does is simply creating beans of the property elements. It injects our base properties class in the constructor and it creates beans of the inner classes, to make them injectable anywhere. The useful aspect of this implementation is the fact that whenever you autowire one of the subclasses, you don’t get all the other properties you don’t need. Basically you just need to grab the properties that are in scope of whatever functionality you’re developing. Obviously you can also grab al the properties whenever needed.

Since our properties class is statefull and it has getters as well as setters, we are also free to change the state of the property values while running the application. This can result in totally different application behaviour, so be careful with it. Perhaps you should add some security checks for the setters access.

To wrap things of, an example extract of a database configuration class that only injects the database properties (other properties aren’t necessary here):

private final CSProperties.Database dbProps;

    @Autowired public MyBatisConfig(CSProperties.Database dbProps) {
        this.dbProps = dbProps;
    }

    @Bean
    public DataSource dataSource() {
        SimpleDriverDataSource dataSource = new SimpleDriverDataSource ();
        dataSource.setDriverClass(com.mysql.cj.jdbc.Driver.class);
        dataSource.setUrl(dbProps.getUrl());
        dataSource.setUsername(dbProps.getUsername());
        dataSource.setPassword(dbProps.getPassword());

        return dataSource;
    }

Bonus: Property Metadata

Code completion and documentation above all. Spring actually makes it possible to attach custom metadata to your properties. IntelliJ actually detects when a property key has metadata, if so, it will provide code completion and additional information. You can also define the datatypes and default values.

Property metadata file.
Property metadata file.

Have your IDE generate a JSON file in your META-INF folder. The file will be called ‘additional-spring-configuration-metadata.json’. If you decide to use such a file, make sure to update it along with the edited property file(s).

Adjust Loading Animations in Vaadin

By default, loading animations in Vaadin are already pretty awesome, though you might want to adjust them to make them fit better with your custom theme.

While tweaking around with the animations myself, I found that there wasn’t too much information to find about it around the web, so here’s me contributing.

It’s All CSS

To adjust the loading animations, there’s actually no need at all to fiddle in Java code. Everything can be easily set up in css. You only need to edit one file, which would be your custom theme’s scss file.

First of all, it is important to know that the styling for the animations is not located under the .v-app class. All the editing can be done top-level, right after the base theme include statement. For the Valo theme, this would be right after the following line: @include valo;.

Top Loading Indicator

In this example I will cover a minor tweak to the loading bar you see on the top of the page, which by default is blue. It is displayed upon page navigation.

To simply adjust the color you can use following code snippet, where all style attributes are just coppied from the default styling. The only property you’ll want to tweak will be the background-color one.

.v-loading-indicator {
    position: fixed !important;
    z-index: 99999;
    left: 0;
    right: auto;
    top: 0;
    width: 50%;
    opacity: 1;
    height: 4px;
    background-color: red;
    pointer-events: none;
    -webkit-transition: none;
    -moz-transition: none;
    transition: none;
    -webkit-animation: v-progress-start 1000ms 200ms both;
    -moz-animation: v-progress-start 1000ms 200ms both;
    animation: v-progress-start 1000ms 200ms both;
}

Connection Lost Spinner

Since we’re at it, we might as well adjust the color of the spinner that shows when the connection was lost. Once again, this snippet must be placed outside the .v-app class. Obviously, if you want to adjust all spinners application-wide, apply the styling to the .spinner class only.

The resulting box with spinner.
The resulting box with spinner.
.v-reconnect-dialog .spinner {
    border-top-color: red;
    border-right-color: red;
}

Centered Loading Spinner

Vaadin’s default spinner is shown upon page refresh, for instance. At least in the Valo theme, it is relatively small. Its’ styling is somewhat basic, so it might be good to give it a more customized touch, like the spinner below.

A custom loading spinner.
A custom loading spinner.

Right along the previously provided css snippet, another one can be placed. Following example shows how to replace the default spinner with our own.

.v-app-loading::before {
    opacity: .8; 
    filter: alpha(opacity=80); 
    width: 100px; height: 100px; 
    background: transparent url(../customtheme/img/spinner.gif); 
}

Update the Vaadin Theme

After these small tweaks in this one file you are all set and ready to check out the result of the applied changes.

Keep in mind that you will need to update the theme first. Vaadin has this Maven plugin com.vaadin:vaadin-maven-plugin:8.0.0, that you can add to your pom.xml. Once added, you can simply update and compile the theme and rebuild your project. Besides that, you will probably have to clear your browser’s cache before reloading your application. If you don’t do that, a previous version of your theme’s css file will be used.

First Impressions On Vaadin

Lately I have been working a bit with Vaadin, a web UI framework for business applications. The framework offers an experience similar to Swing. ‘Similar’ is a very important word here. Vaadin uses a component based approach as well, but it is not at all a carbon copy of Swing.

Vaadin Logo

All Java

The main advantage about Vaadin is that its framework is written in Java, meaning that you could place your UI logic right next to your Java back-end logic. No need to hop from Java to Javascript or whatever other front-end programming language.

All of your UI code will run server-side. Vaadin will take care of server-client communication.

There is one small catch though. Custom styling is done in CSS (scss), so if you want to create a personalized theme, you will have to tweak around quite a bit in CSS files.

Strengths & Shortcomings

Vaadin’s biggest advantage is that you can use it to quickly create decent web application UI. You can even create your own theme fairly easily.

The framework is also struggling with some frustrating flaws. By default, Vaadin lacks the possibility to add Components to a Grid. If you want to do that anyway, you would have to install an addon. If the addon uses a widget set, it isn’t even a straight-forward installation.

Besides that I can provide a good example of an annoying flaw in Vaadin. As I was developing a Window that contained a Grid, I had the requirement to bind a boolean value to a column. The column wouldn’t just contain the boolean value as a String, but it was to be displayed as an OptionGroup with two values, ‘yes’ and ‘no’, with the correct value selected based on the boolean’s value.

The binding process went as follows: I defined a BeanItemContainer and from that I created a GeneratedPropertyContainer. On that container I performed calls of addGeneratedProperty() (for the OptionGroup I made use of a custom PropertyValueGenerator returning the OptionGroup to be displayed) . After all that I called setContainerDataSource() on the Grid. That was binding done, or at least I believed so. Once checking out the result in the UI, I noticed all cells were properly bound to their respective data, except for the OptionGroup one. Even more bizarre was the fact that at the time that a new record was added to the Grid, the data was correctly bound to all the OptionGroup cells. Somehow the Grid didn’t initialize correctly, I figured.

So it was time to find some workaround to this issue. Of course things went all smooth when using a CheckBox in stead of an OptionGroup, but that wasn’t really the requirement. Anyway, while playing around with Vaadin in some other personal project, I found out about vaadin-push. That is basically a dependency that enables you to update the UI from a different thread.

I ultimately fixed the issue by calling grid.getUI().push() right before calling grid.setColumns(). That did the trick, allthough it doesn’t look quite right.

Conclusion

I have been playing with the Vaadin framework for a few weeks now, and I’m sure I haven’t seen half of it yet. Overall I can say I’m satisfied with it, except for some frustrations that can arise on banal aspects. It is really easy to write UI fragments that are easy to read. It isn’t really hard to get into the basics. I also have to say it runs absolutely smoothly on any of my Tomcat configurations.

Overall, the framework is an excellent tool for web developers, but it is also an imperfect one. However, it is good to know that the company takes note of what developers are saying and they are always ready to help out.

If you’d like to see what Vaadin looks like, I strongly suggest you to play around with the Vaadin Sampler.

Clickable Links in Balloon Notifications – IntelliJ Plugin

The other day I took another look at my IntelliJ IDEA Plugin project, ‘Pastebin Unofficial‘ and it’s notifications. At the time of writing this project is in a very early, basic stage, it is rather an idea that hasn’t been worked properly (yet).

Clickable links in notifications

So what the project does at this time, is create a Pastebin paste from the opened document in the IDE. You right click anywhere on the opened file and you select ‘New Paste’. A popup will appear for you to specify a paste title (the filename will be picked by default). When dismissing the dialog, a paste will be sent to Pastebin and a balloon notification will be displayed for a while in the bottom right corner of the IDE.

A balloon notification with link in IntelliJ IDEA.
A balloon notification with link in IntelliJ IDEA.

The goal of the notification was to notify the user that the paste was successfully posted (a different notification would be shown when an error occurred). Only that would not be enough, no, a clickable link to this new paste would be appropriate as well.

Unfortunately, the original attempt didn’t satisfy the requirements:

final Response<String> postResult = Constants.PASTEBIN.post(paste);
NotificationGroup balloonNotifications = new NotificationGroup("Notification group", NotificationDisplayType.BALLOON, true);
    if (postResult.hasError()) {
    //Display error notification
} else {
    //Display success notification
    Notification success = balloonNotifications.createNotification("Successful Paste", "<a href=\"" + postResult.get() + "\">Paste</a> successfully posted!", NotificationType.INFORMATION, null);
    Notifications.Bus.notify(success, project);
}

In fact, it was rather naive to have used a simple html <a href="..."> tag. Even more impulsive was leaving out the required surrounding <html></html> tags.

As if those absolute failures weren’t enough, I also managed to completely ignore the latest parameter of Type NotificationListener. Passing null isn’t really going to do anything there, is it?

After a couple of Google searches I managed to find the solution. When instantiating the notification, I now include the proper surrounding tags and I provide a bit of code handling a click on the hyperlink.

This did the trick in the end:

Notification success = balloonNotifications.createNotification("<html>Successful Paste", "<a href=\"" + postResult.get() + "\" target=\"blank\">Paste</a> successfully posted!</html>", NotificationType.INFORMATION, (notification, hyperlinkEvent) -> {
    if (hyperlinkEvent.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
        BrowserUtil.browse(hyperlinkEvent.getURL());
    }
});

Now links are opening in the default browser. Note that links in the event log are now clickable as well.

However this being a valid solution, another, much cleaner one, is available as well. The final and thus preferable solution looks like this:

Notification success = balloonNotifications.createNotification(
                "<html>Successful Paste", "<a href=\"" + postResult.get() + "\" target=\"blank\">Paste</a> successfully posted!</html>",
                NotificationType.INFORMATION, new NotificationListener.UrlOpeningListener(true));

Find the original question on StackOverflow.

Happy Holidays – 2016-2017

It’s that time of the year again! Holidays are coming up along with the usual festivities. Here’s about my past year and what’s to come in 2017.

Looking back

Overall 2016 was a great year. The major highlight was getting started on my first full time job in Antwerp, Belgium. This was the biggest change in my life so far. I’ve learnt a vast amount of things on the office floor, and that’s more than only technical stuff. I was lucky to work with some very interesting and intelligent people, that enriched me all along.

Whirlpool Rapids
Standing in front of the Whirlpool Rapids defining the border between North America and Canada.

Another big highlight would be the trip I made with my family to Canada during the summer. I’ve never been this far away from home, but I had a great time. Would definitely recommend.

Besides all that great stuff, life went as life goes. There were awesome moments, moments of joy, as well as less pleasant moments.

A new year, new challenges

2017 Will bring more changes. Early January you can expect a small update on my homepage and LinkedIn profile. What I can say is that Java programming will be the core of that change (at my great joy). This will also involve studying for some certificates (including OCA and OCP). Once again, I expect 2017 to be a very enriching year, in general.

You can expect more updates on this blog as well. Most updates are likely to be Java-related and somewhat technical. These updates will be published as I see fit. There’s no need to publish when there’s nothing noteworthy to share. Besides tweeting new articles, I will also share them on a few additional social media. Whenever you’d like to engage with me, I’ll always do my best to read and reply.

Happy holidays and an awesome 2017!

JToolTip Behavior Outside JFrames

As I was working on a small application, I started implementing a custom JToolTip to be used throughout the app, in stead of Swing’s default JToolTip.

The custom JToolTip entirely inside the JFrame.
The custom tooltip entirely inside the JFrame.

Testing the application I was surprised by the behavior of the tooltips when they would exceed the borders of a JFrame (exceeding for a pixel was enough).

In the image below, you can notice that a background (default Swing Color) is present for the tooltip component. This background was not present for the exact same tooltip if it appeared inside the frame. So, the goal was to remove this background.

The custom JToolTip exceeding the JFrame's border.
The custom tooltip exceeding the JFrame’s border.

First thing that came in mind was, ‘I should change the background to a transparent one’. And so I did, by calling this line on the JToolTip (mind the last parameter, the alpha value of the color):

setBackground(new Color(255, 255, 255, 0));<br />

Obviously that didn’t do the trick, but it was one step closer to the solution. In fact, someone pointed out that when the component surpasses the frame’s borders, it is actually added to a JWindow prior to being displayed.

SwingUtilities provides a method that returns the Window of a specified component:

SwingUtilities.windowForComponent(...);

It sufficed to update the background color of the window, in which the tooltip was housed, with a transparent one (alpha value of 0).

As an additional measure I made sure all the parent components of the tooltip were set to be non-opaque.

The final solution could be implemented in the overridden addNotify() method:

@Override
    public void addNotify() {
        super.addNotify();
        setOpaque(false);
        Component parent = this.getParent();
        if (parent != null) {
            if (parent instanceof JComponent) {
                JComponent jparent = (JComponent) parent;
                jparent.setOpaque(false);
            }
        }
        Window window = SwingUtilities.windowForComponent(this);
        try {
            window.setBackground(new Color(255, 255, 255, 0));
        } catch (IllegalComponentStateException e) {
            //Do nothing
        }
    }

In the above code, you may notice the catch block handling potentially raised exception: IllegalComponentStateException. It was vital to add that catch statement in. A tooltip inside a frame, not exceeding the borders, is not added to a JWindow before being displayed. This means no window background should be changed, as there would be no window.

Find the question on StackOverflow for further reference.

In Depth Test Reporting with Allure

Always wanted to do test reporting properly? Allure, an excellent framework to properly report your test runs does just what you’d expect from it.

Test run overview in Allure
Test run overview in Allure

The main purpose of Allure should be clear. It provides in reports, graphs and different types of overviews (including optional attachments and links) to present the status of your System Under Test (SUT).

Allure in a nutshell according to it’s developers:

A flexible, lightweight multi-language test report tool, with the possibility of adding to the report of additional information such as screenshots, logs and so on.

Lightweight and lightning fast, it is, the framework can generate a report site in less then 2 seconds (mvn site). The list of programming languages and test frameworks you can use with the framework is impressive as well. Don’t worry, all the big ones are definitely covered!

Core Functionality

In fact, the features Allure offer are limited, but that’s also it’s great power. Allure tends to make use of Annotations. An example of one of those is the @Step annotation. When a method is annotated with it and the method gets called in one of your tests, it will be included as a reproduction step in an issue overview. You will be able to see when the step started and how long the execution of it took.

Similarly, you could attach screenshots, los, JSon, XML, … To your failed tests for later reference.

@Attachment(value = "Page screenshot", type = "image/png")
public byte[] saveScreenshot(byte[] screenShot) {
    return screenShot;
}

Furthermore you could arrange different test cases under features and stories. This is purely to add some structure to your reports. Make use of @Features and @Stories annotations on your test case classes and/or methods.

Side Info

You could always dig into an example report to see what the end product looks like.

Another interesting thing to note, is that Allure is an open source project initially developed for Yandex, a Russian Google Chrome variant for internal testing. Find it on GitHub. They now claim thousands of software testers are giving the Allure experience a high note and that it’s being used all around the globe.

You would be silly not to take a look at it, as it is such an incredible easy setup, but a tool that can help you, your co-developers and even your product owner(s) (as they might want to get some insights at some point during development). Presenting a snapshot of the SUT status is done in no-time. A good approach would be to generate a new report after every CI build and iteration.

Basically all you need to do:

  1. mvn clean;
  2. mvn site;
  3. mvn jetty:run (as the front-end can be displayed locally using Jetty).

Those are all Maven commands. Make sure your dependencies are all in place in your pom.xml and you are good to go.

Track the Heap With Memory View

With Jetbrains‘ recent plugin, ‘JVM Debugger Memory View’ you can go the extra mile while debugging your applications in IntelliJ IDEA and Android Studio. If you want to keep an eye on the heap, the plugin is a valid tool to use during your debug sessions!

Memory View
A search in the Memory View.

Memory View basically lists a ton of Objects that are placed on the heap at the time present. It gives you the possibility to get a better feel of the current situation (at a breakpoint) of your application, memory-wise. The tool has packed its features inside a new tab in the IDE. You can find it by default in a panel on the right side.

In the overview you can see how many Objects have been added, removed when stepping over code. If you would place a few breakpoints you can easily view how the just executed code has affected the heap.

It is also possible to track new Instances of a particular Object. To do so you will need to turn on this feature for every class name listed.

Achievement instances in Memory View.
Achievement instances in Memory View.

Opening the class instances dialog enables filtering. Apply a filter with an evaluated expression.

Filtering in Memory View.
Filtering in Memory View.

Once you have a desired overview of instances you can unfold instances, just like you already could in the variables section in the regular debug mode. This is great for inspection of the objects. Objects where exceptions were raised properly stand out as well.

Furthermore, there is a possibility to view the call stack of the instance. When an object is selected you can view this in the stack frame on the right.

Another nice feature is the ‘Referring Objects For Object X’ one. To open up this frame, right click on an object and click ‘Show Referring Objects…’. You will now get a thorough overview of every referrer of the selected Object.

If you’ve got IntelliJ IDEA 2016.1 or higher, you can simply install the plugin from the Jetbrains repository.

As a side note I’d like to warn Android Studio users. The IDE may freeze due to a bug still present at the time of writing. Also, getting large amounts of instances could cause problems due to memory restrictions in Android. It seems the development is still ongoing. If you’ve found a bug, you can always log it in their issue tracker.

Programming Unlockable Achievements

So you wrote this game, but would now like to step up? Unlockable achievements is an aspect that enhances your game and it’s fun and interesting to program.

Minecraft Achievement
A simple Minecraft Achievement

The Concept

Let’s elaborate on the actual purpose and the concept of unlockable achievements. Basically you could consider an Achievement to be a milestone. It is a goal your end user achieves, literally. It is up to you to determine these milestones.

Let’s take Minecraft‘s ‘Taking Inventory’ achievement as an example. The achievement is unlocked at the moment the inventory is opened for the first time. This example is a single Achievement, meaning it has no predecessors or successors. Possibly you’d want to create an achievement that could only be unlocked when this one was unlocked first. You may even want to have a set of achievements unlocked before achieving a parent achievement.

The previous example was obviously very simplistic. There was one task, one goal that lead to the unlocking of the achievement. Different achievements might consist of multiple milestones to reach before unlock. Or maybe you’d want specific actions to take place in order to achieve the achievement.

Achievements Everywhere

Gaming companies, publishers and console builders all make use of achievements. Think about the trophies you can earn on PlayStation and XBox consoles. Think about achievements that you can collect on the Steam platform. And don’t forget the achievements on mobile devices in Google Play Games (Android) and Game Center (iOS). There are so many possibilities, so many things you can do with your in-game achievements. You can go beyond an implementation in your game itself.

Implementation

Let’s put things in practice by covering a possible implementation approach in Java.

You want to get things started by defining an interface:

public interface Achievable {
    void achieve();
}

Now we’re ready to define an Achievement class. You can make it Observable as we did in the following example. That way registered observers can get notified at the moment the Achievement is unlocked.

public class Achievement extends Observable implements Achievable {

    private String name, description;
    private List<AchievementProperty> propertyList;
    private boolean unlocked;

    /**
     * Class constructor specifying name, description and properties to be activated.
     *
     * @param name        the untranslated name of the achievement
     * @param description the untranslated description of the achievement
     * @param properties  the properties related to the achievement
     */
    public Achievement(String name, String description, List<AchievementProperty> properties) {
        this.name = name;
        this.description = description;
        this.propertyList = properties;
        this.unlocked = false;
    }

    /**
     * Unlocks this achievement and notifies its' observers.
     */
    @Override
    public void achieve() {
        if (!unlocked) {
            boolean allActive = true;
            for (AchievementProperty property : propertyList) {
                if (!property.isActive()) {
                    allActive = false;
                    break;
                }
            }
            if (allActive) {
                this.unlocked = true;
                setChanged();
                notifyObservers();
            }
    }
//Getters, setters and toString omitted...
}

As you can see in the above code, the achievement contains a list of AchievementProperty. These are properties that need to be active when the achievement is unlocked.

Here’s how the AchievementProperty class may look like:

public class AchievementProperty {

    private String name;
    private int value;
    private String activation;
    private int activationValue;
    private int initialValue;
    private String tag;

    /**
     * Class constructor specifying name, activation, activation value and initial value.
     *
     * @param name            the untranslated name of the property
     * @param activation      the activation method of the property
     * @param activationValue the activation value of the property
     * @param initialValue    the initial value of the property
     */
    public AchievementProperty(String name, String activation, int activationValue, int initialValue) {
        this.name = name;
        this.activation = activation;
        this.activationValue = activationValue;
        this.initialValue = initialValue;
    }

    /**
     * Class constructor specifying name, activation, activation value, initial value and tag.
     *
     * @param name            the untranslated name of the property
     * @param activation      the activation method of the property
     * @param activationValue the activation value of the property
     * @param initialValue    the initial value of the property
     * @param tag             the tag of the property
     */
    public AchievementProperty(String name, String activation, int activationValue, int initialValue, String tag) {
        this.name = name;
        this.activation = activation;
        this.activationValue = activationValue;
        this.initialValue = initialValue;
        this.tag = tag;
    }

    /**
     * Returns true when this property is active, false if otherwise.
     *
     * @return true when this property is active, false if otherwise
     */
    public boolean isActive() {
        boolean flag = false;

        switch (activation) {
            case Achiever.ACTIVE_IF_GREATER_THAN:
                flag = value > activationValue;
                break;
            case Achiever.ACTIVE_IF_LESS_THAN:
                flag = value < activationValue;
                break;
            case Achiever.ACTIVE_IF_EQUALS_TO:
                flag = value == activationValue;
        }

        return flag;
    }

    /**
     * Resets this property's current value.
     */
    public void reset() {
        this.value = initialValue;
    }

Now it’s up to you to get all that linked up by creating the ‘Achiever’ class. I’ll leave that as an exercise to the reader. Here’s a bit more context to get you going:

  1. Make use of a HashMap to keep AchievementProperty instances;
  2. Make use of a HashMap to keep Achievement instances;
  3. Provide a ‘defineProperty’ method that creates and returns a new AchievementProperty based on specified parameters. If the property is not yet listed in the HashMap, put it in there;
  4. Provide a ‘defineAchievement’ method that creates and returns a new Achievement based on specified parameters (do not forget its’ related Achievementproperty/AchievementProperties!). If the achievement is not yet listed in the HashMap, put in in there;
  5. Add a method that will achieve all eligible achievements (don’t forget checks on the related AchievementProperty/AchievementProperties;
  6. Add methods to add/set a value to properties, or even to reset property values.

At this point you can create your new achievements and their respective related property/properties.

On the moment a property needs to get an update, you call the ‘addValue’ method from step 6 and you call the ‘checkAchievements’ method from step 5. This way your achievements can get unlocked at the proper time.