• Fat Cats Boardgame
  • Wicket UI Library
  • About Me

Java and Wicket web development thoughts, tutorials, and tips

roman@coderdreams.com
Coder DreamsCoder Dreams
  • Fat Cats Boardgame
  • Wicket UI Library
  • About Me

Customizing your Wicket codebase: Part 3 – Custom Text

May 16, 2020 Posted by Roman Sery customization, wicket No Comments

In part 1 and part 2 we discussed ways of customizing your codebase to deal with varying requirements for each of your customers. Now let’s talk about another technique using property files that will allow you to customize field labels and other text. We’ll also look at some other uses of property files.

Structuring property files

We will create a default properties file as well as one for every customer that wants to override the defaults. And we’re going to place them inside of the resources folder. You can visual it like this:

txt_content.properties will be our default file. Each customer can override as much or as little as they need to. The customer files will follow the format of “txt_content_{CUSTOMER}.properties”.

Creating the Wicket ResourceLoader

Now we need to create a class that will tell Wicket how to use these files. It might seem like there is a lot going on, but we’ll see that it’s actually quite simple.

public class TxtContentResourceLoader implements IStringResourceLoader {
	private static final Logger log = LoggerFactory.getLogger(TxtContentResourceLoader.class);
	
	private Properties fileProps = null;

	public TxtContentResourceLoader() {
		super();
		initProperties();
	}

	protected String getIdentifier() {
		return "labels/txt_content";
	}

	private void initProperties() {
		if(fileProps != null) {
			return;
		}

		java.util.Properties merged = new java.util.Properties();
		
		java.util.Properties defaultProps = getProperties(getIdentifier() + ".properties");
		if(defaultProps != null) {
			merged.putAll(defaultProps);
		}
		String customer = Utils.getCustomer();
		if(customer != null) {
			java.util.Properties clientProps = getProperties(getIdentifier()+ '_' +customer+".properties");
			if(clientProps != null) {
				merged.putAll(clientProps);
			}
		}

		ValueMap data = new ValueMap();
		Enumeration<?> enumeration = merged.propertyNames();
		while (enumeration.hasMoreElements()) {
			String property = (String)enumeration.nextElement();
			data.put(property, merged.getProperty(property));
		}

		fileProps = new Properties(getIdentifier(), data);
	}
	
	
	private java.util.Properties getProperties(String path) {

        try (InputStream in = TxtContentResourceLoader.class.getClassLoader().getResourceAsStream(path)) {
            UtfPropertiesFilePropertiesLoader loader = new UtfPropertiesFilePropertiesLoader(null, StandardCharsets.UTF_8.name());
            if(in == null) {
                return null;
            }
            return loader.loadJavaProperties(in);
        } catch (IOException e) {
            log.error("failed getProperties({})", path, e);
        }

		return null;	
	}
	
	
	private String load(String key) {		
		if(fileProps == null) return null;
		
		String value = fileProps.getString(key);
		if (value != null) {
			return value;
		}
		
		return null;
	}

	@Override
	public String loadStringResource(Class<?> clazz, String key, Locale locale, String style, String variation) {
		return load(key);
	}

	@Override
	public String loadStringResource(Component component, String key, Locale locale, String style, String variation) {
		return load(key);
	}

}

What we’re doing here is:

  1. Load all the properties from our defaults (txt_content.properties) into a map.
  2. Next, if there is a file for the current customer, load those properties as well.
  3. Now we need to combine or merge them into a “merged” map so that the customer-specific key/values overwrite the entries in the default map.

Let’s use it!

To use our new resource loader, we just need to register it with our Wicket application. We do it inside of our init() method for the WebApplication:

getResourceSettings().getStringResourceLoaders().add(new TxtContentResourceLoader());

Let’s define some very simple properties:

txt_content.properties:
user.address.zip.lbl=Zip Code
user.address.state.lbl=State

txt_content_FB.properties:
user.address.zip.lbl=Zip/Postal Code
user.address.state.lbl=State/Provence

To actually use these properties in our web pages we can do something like this:

add(new Label("zip", getLbl("user.address.zip")));
add(new Label("state", getLbl("user.address.state")));

Wicket will now know to use the correct version depending on which customer is set in the JVM parameters.

Other uses

We’ve only looked at a simple example of customizing labels. However, you can use this technique to do a lot more:

  • You can allow customers to override the default visibility of fields by using a “hidden” property (user.address.zip.hidden=1)
  • You can set validation rules such as not requiring a certain field (user.address.zip.required=0)
  • You can allow customers to make some fields read-only (user.address.zip.readOnly=1)
  • Use your imagination!

The full source code can be found on GitHub, enjoy!

No Comments
Share
1

About Roman Sery

I've been a software developer for over 10 years and still loving Java!

You also might be interested in

Using interfaces to make Java enums more flexible

Jul 10, 2019

Imagine you need to easily customize your enumerations for each customer but want to have one codebase? Here's how

Rent Day

Rent Day

May 12, 2021

I’m happy to announce the launch of Rent Day! If[...]

Wicket quick tip #5: Prevent duplicate appendJavascript() invocations

Aug 12, 2020

Implement a custom AjaxRequestTargetProvider to prevent duplicate Javascript being sent to the browser.

Categories

  • aws
  • customization
  • database
  • debugging
  • enum
  • java
  • models
  • performance
  • projects
  • react
  • software design
  • Spring
  • tool
  • Uncategorized
  • wicket

Recent Posts

  • Rent Day
  • Self-contained Wicket Fragments
  • Pros and cons of unit testing
  • Themeable React Monopoly board
  • Please dont use client-specific release branches

Recent Comments

  • TCI Express Thanks for sharing such insightful information. TCI Express truly stands out as the best air logistics company, offering fast, secure, and efficient air express and cold chain transportation services....

    Tracking down a bug in production Wicket application ·  March 25, 2025

  • Tom Error: A zip file cannot include itself Can you please correct the plugin part so it doesn't use the same folder as input?

    Deploying Spring Boot app to AWS Beanstalk with Nginx customization ·  September 3, 2021

  • Golfman: Reality always wins I've used both Wicket and front-end JS frameworks and, having worked extensively on both, I can tell you that "Speed of development" is definitely NOT with the JS frameworks. You basically end up...

    Five reasons you should use Apache Wicket ·  August 29, 2021

  • Kiriller Sorry can not agree with you, wicket might be a well built technical framework. But the advantages of using a front-end framework like react.js and vue.js can not be beaten by Wicket nowadays. - Speed...

    Five reasons you should use Apache Wicket ·  August 23, 2021

  • Bernd Lauert Sorry but i have to refute your claims with the following arguments: 1. the Wicket community may be small but it is also very responsive, you usually get a helpful answer from the core devs on the...

    Five reasons you should use Apache Wicket ·  July 1, 2021

Archives

  • May 2021
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • November 2019
  • October 2019
  • September 2019
  • August 2019
  • July 2019

Contact Me

Send Message
Prev Next