Our Blog

Let us find tech solutions together

Nov 04

After meeting Talip Ozturk at Java2Days in Sofia back in October, I was inspired to take Hazelcast out for a test drive. What better way to do this, than to throw it head first into our little pet project pastebin! After perusing the well put together documentation on the project’s website, I set out modifying the codebase to additionally support Hazelcast as a storage mechanism.

I aim to keep this short and sweet, find the latest code to download including Hazelcast. We’ll go over:

  1. How to get access to a Map of your own
  2. The hazelcast.xml file for configuration
  3. Adding listeners for CRUD events
  4. Rebuilding our pastes if container dies

A map of your very own

Our super clustered highly scalable data distribution platform has a lot of really cool features, and for now … we just need a Map. The nice thing about Hazelcast is getting a cluster together is a fairly short bit of Java code, and away we go. The hazelcast core jar comes with a great command line tool for testing things and can be run like this:

1
java -Djava.net.preferIPv4Stack=true -cp hazelcast-1.7.1.jar com.hazelcast.examples.TestApp

Hazelcast uses namespaces to differentiate datasets, for our purposes we just need one namespace and we’re calling it “default”. Here’s the code that grabs a Map from the Hazelcast cluster:

1
        IMap map = Hazelcast.getMap(namespace);

When we save a paste, if its public we save only the long id, and if its private we also save the unique key which points back to the paste id for lookup purposes:

1
2
3
4
5
6
7
8
9
10
11
12
        IMap map = Hazelcast.getMap(namespace);

        item.setId(((MysticPasteHazelcastApplication) Application.get()).nextId());

        map.put(item.getId(), item);

        if(item.isPrivate()) {
            map.put(item.getPrivateToken(), item.getId());
        } else {
            List<Long> indexList = ((MysticPasteHazelcastApplication) Application.get()).getIndexList();
            indexList.add(item.getId());
        }

Grabbing a history of pastes utilizes our generated indexList which is a CopyOnWriteArrayList so special fun is taken to sort and reverse the list, and splice it for the return to our DataProvider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        List<Long> list = ((MysticPasteHazelcastApplication) Application.get()).getIndexList();

        if(list == null) return Collections.EMPTY_LIST;

        // CopyOnWriteArrayList doesn't give us the ability to sort and reverse, so we put in a regular ArrayList for the "find"
        List<Long> unsafeList = new ArrayList<Long>(list);
        Collections.sort(unsafeList);
        Collections.reverse(unsafeList);

        List<Long> pageIds = unsafeList.subList(startIndex, (unsafeList.size() < (startIndex + count) ? unsafeList.size() : (startIndex + count)));
        List<PasteItem> pagedList = new ArrayList<PasteItem>();

        for (Long pasteItemId : pageIds) {
            pagedList.add((PasteItem) map.get(pasteItemId));
        }

So you can see, we’re dealing with very simple conventions to save our data, denormalized to work with the key/value storage mechanism. Fun, right?

Yes, ma there's an xml config file

While I don’t love configuration done in XML, this one is simple enough. You can read up on some of the options available to you on the Hazelcast wiki.

Is anyone listening to this?

In order to provide the paged history functionality available in the pastebin, we have to keep all id’s in an application scoped list. And Hazelcast doesn’t disappoint in allowing you a really clean and simple method of achieving this with it’s Distributed Events. Here’s how we achieve what we want with the pastebin:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        IMap map = Hazelcast.getMap(namespace);

        map.addEntryListener(new EntryListener() {

            public void entryAdded(EntryEvent entryEvent) {
                if (entryEvent.getValue() instanceof PasteItem) {
                    PasteItem pasteItem = (PasteItem) entryEvent.getValue();

                    if (!pasteItem.isPrivate()) {
                        indexList.add(pasteItem.getId());
                    }
                }
            }

            public void entryRemoved(EntryEvent entryEvent) {}
            public void entryUpdated(EntryEvent entryEvent) {}
            public void entryEvicted(EntryEvent entryEvent) {}
        }, true);

As you can see, we are notified whenever an entry gets added, and we proceed to add it to our growing application scoped list if it’s a public paste. We put this block of code in a constructor or init() block of our extended WicketApplication.

We can rebuild it, we have the technology

So now we have a nice cluster setup, we’ve got pastes being saved and our list being populated so the history page works. What if the container dies? We still have our cluster in place, so the paste data is “backed up” and can get reattached, but our application scoped list of paste id’s, will be empty. We solve this by iterating over the existing Map, and rebuilding our list upon the start of the Application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
        List<Long> initialIndexList = new ArrayList<Long>();

        if (lastIdentifier.longValue() == 0L && indexList.size() == 0) {
            // rebuild our index list and lastIdentifier
            Set keys = map.keySet();
            for (Object key : keys) {
                if (key instanceof Long) {
                    Object keyValue = map.get(key);
                    if (keyValue instanceof PasteItem) {
                        PasteItem pasteItem = (PasteItem) keyValue;
                        if (lastIdentifier.longValue() < pasteItem.getId()) {
                            lastIdentifier = new AtomicLong(pasteItem.getId());
                        }
                        initialIndexList.add(pasteItem.getId());
                    }
                }
            }

            Collections.sort(initialIndexList);
            indexList = new CopyOnWriteArrayList<Long>(initialIndexList);
        }

Next steps

The rest of the code can be reviewed, and of course run using the Maven build tool. One thing that would probably make it into a production version that hasn’t been discussed here is persistence upon cluster failing - if the whole thing dies, we need to store this in a more permanent location. See the Persistence page on the Hazelcast wiki.

Here at Mystic we certainly like seeing new tools that can make our jobs easier, and it certainly looks like Hazelcast fits that nicely.

Read more
Nov 02

Andrew with Duck on Head

Last month in early October, I attended the Java2Days conference in Sofia, Bulgaria. This being the first conference put on in the Balkans and one that reached out to an international set of speakers, I wasn’t expecting it to be any different than the other myriad of conferences. Boy was I wrong. The organizers put everything together so well, that each of the speakers and a lot of the attendees that I spoke with were impressed with the organization.

The event was over a two-day period and the speakers ranged from front-end web frameworks / j2ee to really slick talks on OSGi, Cloud, and distributed key-value storage (all the rage these days). The sessions were a bit on the short-side, and that meant a little trimming was involved in each talk, with only the most important information staying in. All the usual schwag was given out, with the addition of what I can only describe as “booth babes” walking around handing out little slips of the next two upcoming speakers while wearing matching devil / angel costumes. Awesome.

The organizers were so accommodating I think we all grew to love our visit to Sofia that much more. We were greeted at the airport and personally taken out for dinner when we arrived, and every night after that was some special event for the speakers. In fact, of my entire trip in Europe one of the most memorable was the dinner we had after the first conference day. It was great food, belly dancers, and a super festive crowd dancing for hours and hours. We all had a lot of fun throughout, and being taken care of during our stay, makes Java2Days the conference to attend for us next year.

Thanks again to all the organizers, speakers I met, and all who attended the conference.

Read more
Oct 06

(Editor’s note: Olivier Croisier contributed this column from YesWicket.)

Enums are a convenient way to represent finite collections of elements : seasons, week days… As a consequence, they frequently need to be input or displayed in web applications - and it better be in a I18N-aware way. Let’s see how easily Wicket can handle this.

Enums internationalization

Throughout this article, we’ll use the Seasons Enum as an example :

1
2
3
public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER;
}

Wicket has a powerful hierarchical I18N system : given a logical I18N key (a string), the corresponding translation is first searched for at the current component level, then up its hierarchy - all the way up to the Application root if required. To benefit from it, the developer only has to call the getString() method on any Wicket component :

1
String translation = anyComponent.getString(key);

The first thing we need to do is therefore to devise a way to generate a unique I18N key for each Enum constant. The most obvious solution is to use their Fully Qualified Names as a key (eg. “com.yeswicket.wickettips.model.WINTER”) ; this should prevent fortuitous name clashes.

The following code snippet demonstrates how to get an Enum’s FQN :

1
2
Season enumValue = Season.WINTER;
String messageKey = enumValue.getDeclaringClass().getCanonicalName() + "." + enumValue.name();

In order to avoid copy/pasting this code all around the application, and to be able to easily replace it with another algorithm should the need arise, we’ll use the Strategy pattern, where every algorithm is encapsulated in its own class. This might seem easy to implement, but keep in mind that every class accessible from a Wicket component will be serialized along with it in the session store… and that’s something you will definetely want to avoid.

Static methods to the rescue ! The following class, inspired from java.util.Locale, has a static-only API for its consumers (thus solving the serialization concern) and still allows the underlying algorithm to be changed at will :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public abstract class EnumMessageKeyProvider {
	private static EnumMessageKeyProvider provider = new DefaultEnumResourceKeyProvider();

	public static EnumMessageKeyProvider getDefault() {
		return EnumMessageKeyProvider.provider;
	}

	public static void setDefault(EnumMessageKeyProvider provider) {
		EnumMessageKeyProvider.provider = provider;
	}

	public abstract <t extends Enum<t>> String computeMessageKey(T enumValue);

	public static <t extends Enum<t>> String getMessageKey(T enumValue) {
		return EnumMessageKeyProvider.provider.computeMessageKey(enumValue);
	}
}
public class DefaultEnumResourceKeyProvider extends EnumMessageKeyProvider {
	@Override
	public <t extends Enum<t>> String computeMessageKey(T enumValue) {
		return enumValue.getDeclaringClass().getCanonicalName() + "." + enumValue.name();
	}
}

Getting an I18N key for an Enum is now as easy as :

1
2
Season enumValue = Season.WINTER;
String key = EnumMessageKeyProvider.getMessageKey(enumValue);

To use another key generation algorithm, just write a new strategy…

1
2
3
4
5
6
public class SimpleNameEnumResourceKeyProvider extends EnumMessageKeyProvider {
	@Override
	public <t extends Enum<t>> String computeMessageKey(T enumValue) {
		return enumValue.name();
	}
}

…and register it with the EnumMessageKeyProvider ; a good place for that is the Application’s init() method :

1
2
3
4
5
6
7
public class WicketTipsApplication extends WebApplication {
	@Override
	protected void init() {
		EnumMessageKeyProvider.setDefault(new SimpleNameEnumResourceKeyProvider());
	}
	(...)
}

Displaying internationalized enums

Wicket’s Label is a very basic component that simply displays the text provided by its Model. To display Enums, we can develop a new kind of Model that automatically performs internationalization and hands over the resulting text to the component it is attached to.

As an example, we’ll extend the very convenient PropertyModel. Please note that our Model provides a String but operates on an Enum : EnumPropertyModel<t extends Enum> extends PropertyModel. Also, in addition to the PropertyModel's existing constructor parameters (the target object and the name of the property to retrieve), our class needs a Component to call the getString() method on.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class EnumPropertyModel<t extends Enum<t>> extends PropertyModel<string> {

	private Component component;

	public EnumPropertyModel(Object modelObject, String expression, Component resourceProvider) {
		super(modelObject, expression);
		this.component = resourceProvider;
	}

	@Override
	public String getObject() {
		final String expression = propertyExpression();
		final Object target = getTarget();
		if (target != null) {
			T enumValue = (T) PropertyResolver.getValue(expression, target);
			String key = EnumMessageKeyProvider.getMessageKey(enumValue);
			return component.getString(key);
		}
		return null;
	}
}

This custom Model can now be used with a Label (and many other components) to easily display any Enum :

1
2
3
4
5
6
public class HomePage extends WebPage {
	private Season season = Season.SPRING;
	public HomePage() {
		add(new Label("label", new EnumPropertyModel<season>(this, "season", this)));
	}
}

Selecting an enum with a DropDownChoice

Now that we can display an Enum, let’s see how to let the user choose one from a dropdown list.

The DropDownChoice component follows the MVC pattern :

  • The DropDownChoice itself is the Controller
  • The Model it takes as a parameter is, obviously, the Model
  • The View is rendered by a ChoiceRenderer that is responsible for the HTML
Read more