aspose file tools*
The moose likes Java in General and the fly likes Design advice on how to implement preferences and language support Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Design advice on how to implement preferences and language support" Watch "Design advice on how to implement preferences and language support" New topic
Author

Design advice on how to implement preferences and language support

Stephane Eybert
Ranch Hand

Joined: Mar 15, 2010
Posts: 34
Hello,

I have a legacy php application which has multiple modules, each one having a set of preferences supporting language localized strings.

For example, the "document" module has the following preferences:



The language text strings are stored in text files sitting in the file system next to the script like:

DocumentUtils.php
.DocumentUtils.en.php
.DocumentUtils.se.php

Here is the content of one such language text file:

[ 0]Document to download:
[ 1]Download the document
[ 2]Ref:
[ 3]Download
[ 4]Display all the documents:
[ 5]By default, when no category has yet been selected by a visitor of the website, only the documents of the first category are displayed.\n\nBut it is possible to display all the documents instead of only the ones of the first category.
[ 32]Number of documents per row:
[ 33]The lists of documents can display several documents per row.\n\nThe number of documents per row can be modified.\n\nThe number of images per row can be modified.
[ 6]Hide the selector:
[ 7]By default, a category selector is displayed on top of the list of documents.\n\nBut this selector can be hidden to prevent the selection of another category.

The preferences values are stored in a database table:

mysql> desc preference;
+---------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| version | int(10) unsigned | NO | | NULL | |
| name | varchar(50) | NO | UNI | NULL | |
| value | text | YES | | NULL | |
| type | int(10) unsigned | NO | | NULL | |
+---------+------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

mysql> select * from preference limit 10;
+----+---------+----------------------------+-------------+------+
| id | version | name | value | type |
+----+---------+----------------------------+-------------+------+
| 1 | 0 | FLASH_INTRO_HIDDEN | 1 | 1 |
| 2 | 0 | FLASH_INTRO_DISPLAY_ONCE | 1 | 1 |
| 3 | 0 | FLASH_INTRO_DISPLAY_PERIOD | 0 | 7 |
| 4 | 0 | FLASH_INTRO_POPUP | 1 | 1 |
| 5 | 0 | FLASH_INTRO_PAGE_BG_COLOR | | 8 |
| 6 | 0 | FLASH_INTRO_SKIP_LINK | | 2 |
| 7 | 0 | FLASH_INTRO_POPUP_WIDTH | 900 | 2 |
| 8 | 0 | FLASH_INTRO_POPUP_HEIGHT | 900 | 2 |
| 9 | 0 | CLOCK_DATE_NUMERIC_FORMAT | %d-%m-%Y | 6 |
| 10 | 0 | CLOCK_DATE_FORMAT | %A %e %B %Y | 6 |
+----+---------+----------------------------+-------------+------+
10 rows in set (0.00 sec)

And so now I wonder how to go to code a preference manager that would be compatible with the existing data.

I already have the data access layer in Java including domain class, mutators and finder..

But I still need the coupling with the hard coded names in the code and the languages text strings.

Any tip would be welcome.

Thanks !

Stephane

Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19760
    
  20

I think you should check out ResourceBundle. It's one of the most useful classes when dealing with internationalization (no wonder they shorten that to I18N!).


SCJP 1.4 - SCJP 6 - SCWCD 5 - OCEEJBD 6
How To Ask Questions How To Answer Questions
Stephane Eybert
Ranch Hand

Joined: Mar 15, 2010
Posts: 34
Thanks Rob. I used the ResourceBundle class in the past.

My issue lies more with the constants and how to load them:



I guess I could have in each module, an enum along the lines of:

public enum Preference {

DOCUMENT_NB_PER_ROW("My label1", "My help1", PREFERENCE_TYPE_RANGE, array(1, 10, 3)),
DOCUMENT_DISPLAY_ALL("My label2", "My help2", PREFERENCE_TYPE_BOOLEAN),
DOCUMENT_HIDE_SELECTOR("My label3", "My help3", PREFERENCE_TYPE_BOOLEAN);

private String label;
private String help;
private int type;
private Array possibleValues;

Preference(String label, String help, int type) {
this.label = label;
this.help = help;
this.type = type;
}

Preference(String label, String help, int type, Array possibleValues) {
this.label = label;
this.help = help;
this.type = type;
this.possibleValues = possibleValues;
}

public String getLabel() {
return this.label;
}

public String getHelp() {
return this.help;
}

public String getType() {
return this.type;
}

}

As I would have such an array in each module of the application, would it be possible to have each enum class extend on a common one ?

Something like an enum extending anoterh base enum:

http://freddy33.blogspot.com/2007/05/why-java-enum-cannot-extends.html
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19760
    
  20

Unfortunately not. You can never have an enum explicitly extend a class; they all extend java.lang.Enum automatically.
Stephane Eybert
Ranch Hand

Joined: Mar 15, 2010
Posts: 34
I could skip the enum then.

Any design advice ?
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19760
    
  20

You can mimic an enum for all features except the possibility to use it in switch statements.
First, you start by making all constructors private.
Second, you just create a couple of public static final fields of the same type that represent your enum constants.
That already gives you the bulk of the functionality. The rest can be added as needed.
Stephane Eybert
Ranch Hand

Joined: Mar 15, 2010
Posts: 34
Ok Rob, I shall try that road then, cheers.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39818
    
  28
I think this question is too difficult for “beginning”, so I shall move it.
Stephane Eybert
Ranch Hand

Joined: Mar 15, 2010
Posts: 34
I tried to come up with a design but I'm mildly satisfied with my production here.

So here is what I did.

There is a common Preference class:



Which is used by other Preference classes, each for a module of the application:



The application module can then read the preference value with:



I don't know why, but I don't like it.
Stephane Eybert
Ranch Hand

Joined: Mar 15, 2010
Posts: 34
I think the preferences of one module should sit in an array so as to be traversable and displayed in a list.
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19760
    
  20

Stephane Eybert wrote:

1) All of those constants should be static, not just the first one.
2) I would instead use a nested enum:
After that you replace all of those int types to Type. For instance:

I don't know why, but I don't like it.

Why not? Your common Preference class actually looks quite a lot like java.lang.Enum, and your "concrete" Preference class looks like an enum class.

All that you're now missing (apart from stuff like serialization) is the static valueOf() and values() methods. You can get those to work with a few static utility methods. Inside your common class you add global support, using reflection:
Each Preference subclass now gets a little code to support this:

For the pseudo code you should look at the methods of java.lang.reflect.Field, java.lang.reflect.Modifier and java.lang.Class. The exceptions thrown by field.get(null) can be caught and printed; they won't occur since the field is checked to be public, static and final. That means that a) an IllegalAccessException won't occur, b) an IllegalArgumentException won't occur, and c) a NullPointerException won't occur.
Stephane Eybert
Ranch Hand

Joined: Mar 15, 2010
Posts: 34
I tried a new take, this time not using the enum construct.






Stephane Eybert
Ranch Hand

Joined: Mar 15, 2010
Posts: 34
Hello Rob,

I just see your last post, sorry for not having seen before, strange because I made sure to refresh the page before my last post.

Stephane

 
 
subject: Design advice on how to implement preferences and language support