Java Developer Guide
Contents |
Becoming a new developer
- Workspace of: Java Developer
- Main Guides
- Java Developer Guide
- Active tickets (Trac)
- Workspace's Tickets
- Please read the general member guide
- In order to be registrated, a developer have to code at least one significant task and to accept the Team rules. The project appreciates the code quality. Of course, maintainers can help and most commits should be pair-reviewed.
- The best way to provide code is to fork jajuk from gitorious and to perform a request for merge(see Git).
- This code may be a unreserved feature implementation chosen from the task list or of him own choice.
- Important : Please communicate with the Jajuk maintainers (via the ticket) before actually beginning to code a feature so we can design it collaboratively and meet Jajuk rules and standards.
Source Code Management
Jajuk uses GIT since 2011. All inscriptions can be found at the Jajuk Git page.
Natural Language
Jajuk team communication, code and comments have to be in English natural language only.
Copyright
- A single moral entity named "The Jajuk Team" owns the copyright on all sources, please do not set your name in the file headers (BTW, make sure to use the provided code generation template, see bellow).
- Note that your credits are still available from various members lists and from the SCM system anyway.
Developers mailing Lists
- Jajuk developer mailing list is the project main communication stream. Subscription form is here. Note that the Reply-to is directed to the original sender, not the list so please use the "Reply all" button from you e-mail client to reply to the list.
Java version
- Jajuk has to run on every JVM >= 1.6
- Prefer using Java 5+ classes and features (like collection for instead of iterators or, autoboxing, enums). Using generics is mandatory.
IDE
We recommend the Eclipse platform. All following documentation (SVN...) deals with Eclipse only.
Eclipse configuration
- We use basically Eclipse built-in formater configuration with:
- Line length = 100 (instead of 80 by default)
- Tabs = 4 spaces.
- Indentation : 2 spaces.
- Formater profile should be "Unmanaged" (this profile means you use the SCM conf file)[1]. To change the profile and share the changes, the only way we know is to hand-edit the .settings/<file> and commit/push it.
- Only use UTF-8 and Unix-flavor new file carriage return for your source. Check these setting by selecting the project in the Package explorer -> Properties.
- ↑ Eclipse online doc : "If your project is shared, e.g. through CVS, and uses a formatter profile which is not managed by yourself (you have not created the profile) then the profile will be marked as Unmanaged Profile. You are not allowed to change such a profile, only the creator (manager) of the profile can change it. "
Check your .properties file uses correct encoding (due to Eclipse known issue) by selecting file/properties/info. If the file is in ISO8859-1, set UTF-8 instead.
- Templates: in Preferences / Java / Code Style / Code templates, please import this file. This is a template for new java sources
Run configuration
- See default configuration:
Program arguments are currently:
-ide -test
- -ide argument tells jajuk that it is executing inside an IDE (probably Eclipse) . This changes the resources path (images, doc...).
- -test argument tells jajuk to use the ~/.jajuk_debug repository and not the ~/.jajuk, reserved for stable releases (this way a jajuk developer can use a stable release of jajuk when working on a new release) .
VM arguments are currently:
-client -Xms20M -Xmx512M -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -Djava.library.path=lib
Ant scripts
You shouldn't have to use any provided ant script when under Eclipse environment. Two ant scripts are found in the tree:
- scripts/build.xml : this is the stored build file packaged with the distribution and used in command line to recompile Jajuk using a standard installation. It is also used by the packager to generate Jajuk distribution. Do not use it under Eclipse.
Code conventions
Eclipse formatter and templates
- Defaults templates are provided as Eclipse preference with the project. They are mainly Eclipse defaults templates with the Jajuk header for new files
- Defaults code formatter configuration is provided as well with the Eclipse project preferences. It is the Eclipse 3.3 default template except a 100 for line max length.
- Don't use one line statement without braces: use if (){..one line..}, not if (...) one line
- Note that the release packager applies source and import formatting over all the code at each release to make sure the formatting is always applied
String externalization
- All application labels have to be externalized (see Translator Guide) as <Class name>.<number from 0> .
- For common labels like OK, Cancel... we use generic externalized labels (see jajuk.properties). Please keep number of generic labels to minimum and when creating new generic labels, keep in mind that some language (French, German...) are gender-specific in opposition to English.
- Do not reuse existing label ids but always increment a new number for new strings because removed labels can still be present in out-of-date langpacks. For the same reason, leave a comment in the English langpack if your remove the last label of a class (to avoid another developer to use the same ID). For exemple if a class Foo contains 15 labels Foo.0, Foo.1... Foo.14 and if you have to remove Foo.14, leave a comment #Do not use Foo.14, continue to Foo.15.
- Make sure to cleanup useless labels to reduce translators work.
- Debug logs are not externalized string but raw English strings.
Interfaces
Begin interfaces with a upper ' I '. The 'i' is not taken into account for variables naming:
IPerspectiveManager pm;
XML
- Avoid to use PCDATA values, use attributes instead : it's faster to parse and easier to code
- Use single quotes, not double quotes.
Comments
- For formatting reasons, use /* */ for long comments in the methods, not several //
Dead code
Please remove any dead code, SCM helps to recover any previous code anyway.
Tip : install http://www.ucdetector.org eclipse plugin.
Real time TDD
We encourage developers to perform real time TDD using Infinitest :
(Eclipse plugin at http://infinitest.github.com/ )
The project contain an Infinitest configuration out of the box.
Class headers
- Please use the standard Jajuk header (see Eclipse templates configuration). Please do not use your own copyright but keep "The Jajuk Team" as owner.
- Make sure to use the template provided as Eclipse project preference
Code quality
Please keep Eclipse standard level of warnings (imports, static context...) and make sure to cleanup imports (Control-Alt-o).
GUI threading conventions
- Every widget creation or change has to be done inside the EDT (Event Dispatching Thread). For more details, check |1] and [2]. This is currently endorsed through the Substance look and feek (framework?) we use.
- Tasks that takes half a second or more to run (for a large collection) have to be done outside the EDT.
- When an operation requires long operations (done outside the EDT) and GUI updates afterwards (like downloading a picture and then displaying it), you have to use a SwingWorker (the JRE 6 implementation).
- For views that provides a populate mechanism, use the Jajuk "TwoStepsDisplayable" pattern that abstracts the SwingWorker and makes code easier :
- Your view shall implement the TwoStepsDisplayable interface and provide longCall() and shortCall() methods for actions done respectively outside and inside the EDT.
- Use the UtilGUI.populate(TwoStepsDisplayable) method to populate the view and run the underlying SwingWorker.
Documentation
- Please document your features in English on this Wiki ( Jajuk Manual).
- You may want to add new tips of the day in jajuk_properties file.
Code review/fixes
- Jajuk entire code can be updated by anyone if justified (in commit comments). We encourage the peer review and people to work on multiple software areas.
- An e-mail including diffs is sent automaticaly to the jajuk-commits mailing-list at each commit, please subscribe to this list.
Layout Manager
- Jajuk official layout manager is the excellent MigLayout. Please read the quick start guide and the cheat sheet.
- Please use MigLayout in priority for every layout need, even simple cases as the resulting code is extremely simple to write, read and maintain. There are very few cases where you have to use others layout managers (like an Horizontal alignment between two items) or special cases (FlowLayout in CatalogView for ie)
- An excellent | Cheat Sheet is available.
- Please read the Tutorial at http://www.miglayout.com/
- MigLayout is *really* powerful and simple. Even if it supports cell-kind layout management (like grid bag or TableLayout), Please try avoid to use them when possible (what happens when you want to add a widgets among existing elements in the future ?) but use the regular "wrap" mode instead (tell explicitly that you reached the end of a row), "split" and "span".
- In 99% of cases you don't need any inner panel
- MigLayout saves a lot of swing code like insets, setMaxSize, set horizontal/vertical gaps with Box etc... All of these information have to be set as MigLayout string constraints mainly within its constructor.
Validation
- To validation fields in forms, we use | Simple-validation, that's pretty good and non-intrusive.
- See DeviceWizard for an example and see the official documentation at http://kenai.com/projects/simplevalidation/pages/Home .
Wizards
- Use | QDWizard to write complex wizards (see DJWizard as a example)
- Official documentation is available at http://qdwizard.sourceforge.net/doc.html
- QDWizard is a jajuk sub-project, its code base is available in the jajuk trunk, so no jar to import
- Note that QDWizard contains its own problem and validation scheme, we normally don't have to use an external validation lib when writing a wizard.
Unit Testing
- Jajuk uses JUnit unit testing which is well integrated into Eclipse (Development IDE), Hudson (Continuous integration server) and Sonar (Code Quality Checking tool)
General Guidelines
- Guidelines
- The following guidelines should be observed when committing code changes:
- A separate directory is used for tests under src/test/java
- Each class has it's corresponding test case in the same Java package under src/test/java/...
- When implementing new features, please also create corresponding unit test cases or even better, follow Test Driven Development.
- When changing existing classes, run related unit tests before checking in.
- It is not mandatory to run all tests manually on your machine, however please take a look at the Hudson build server after the next automated build and test run (usually done overnight) to ensure that no other test is broken now.
- Fix any unit test broken by your commit quickly to avoid lengthy periods of broken Hudson builds!
Utility classes/Helper methods
There is one class available as part of the current tests that provides basic helper methods: JUnitHelpers. This class can be used for a number of small tasks that are often necessary when writing Unit Tests, it provides the following:
- createSessionDirectory(): Creates a temporary working directory for Jajuk which can then be used for Workspace related tests.
- testPrivateConstructor(): In some cases we add a private consturctor to classes that only have static members to prevent this class from being instantiated (which makes no sense at all). In order to get coverage for this constructor, we have a small helper:
// helper method to emma-coverage of the unused constructor
public void testPrivateConstructor() throws Exception {
JUnitHelpers.executePrivateConstructor(<yourclass>.class);
}
- EqualsTest()/CompareToTest()/ToStringTest()/CloneTest()/HashCodeTest()/EnumTest(): These are helpers for testing the standard methods that are available in many classes, e.g. EqualsTest will verify many general "rules" on equalness that are specified by the Java language definition and which can have side effects if not implemented correctly.
- clearSwingUtilitiesQueue()/waitForThreadToFinish()/waitForAllWorkToFinishAndCleanup(): Helpers when testing Swing-related code. They allow to clean out the queue of asynchronous events and also to wait for threads and other things that are started. This avoid hard to trace errors in tests when things are started in the background by some classes.
- getFile(): creates and registers a music-file.
- getTrack(): creates and registers a music-track.
- MockPlayer: A helper class that implements the Player interface.
Additionally we provide a class JajukTestCase which calls the waitForAllWorkToFinishAndCleanup(). This is useful when testing classes that always require cleanup before starting tests.
Headless mode
In order to have Unit tests running on Continous Integration platforms like Hudson and Sonar, all unit tests must run without UI interaction and without accessing any of the UI functionality from AWT/Swing. Naturally this prevents some things from being tested via unit tests, but on the other hand it ensures that all tests execute without popping up a message box and waiting endlessly for the user to press a button, something that is not useful for unit tests at all.
In order to run the unit tests locally with the same setting to disable UI support in Java, please add the following setting to the run-configuration of Eclipse or any tool used to execute unit tests:
-Djava.awt.headless=true
As result of this, any place where UI is used will throw an "HeadlessException" that we need to ignore for tests, i.e. the test should still succeed, even if the HeadlessException is thrown.
Development hits and available features
Guava
From Jajuk 1.9.6 (and especially 1.10), we rely open Guava, the excellent toolbox from Google. Don't hesitate to use features from Guava (Jajuk 1.9 uses Guava R11) to reduce the number of code lines and increase the code quality. Check Guava javadoc.
Using managers
Managers are the only way to access (list or change) items (Track, File, Type, Directory, Playlist, PlaylistFile, Device, Artist, album and Genre). For example, listing devices is done this way:
DeviceManager.getInstance.getDevices()
Note that getXXXs() methods return copies that can be changed safely.
Anonymizer
- For any private data (track name, user info...), use {{ braces in logs. Example for Cover URL search:
Log.debug("Search URL: Template:"+sURL+"");
- All strings between "{{" and "}}" are automaticaly replaced by "***" in quality agent.
- Use this method to get a list of tracks for a given item like an artist or an album : TrackManager.getAssociatedTracks()
Utilities features
- The org.jajuk.utils.Util* classes contains many useful methods. Please check it to avoid reinventing the wheel but don't hesitate to add new features by yourself.
Files filters
- Jajuk provides a powerful JajukFileFilter class to filter files. Example: to keep only audio files or directories:
new JajukFilter(false,JajukFileFilter.DirectoryFilter.getInstance(), JajukFileFilter.AudioFilter.getInstance());
- Jajuk provides several predefined filters: Audio, NotAudio, Playlist, Directory, KnownType, AnyFile than can be used in conjunction using a AND or an OR between them.
Collection filters
- Jajuk uses Jakarta Commons-Collections features to filter collections. Filtering is done by using decorated iterators using Predicates. Example:
Iterator it = new FilterIterator(tracks.iterator(), new JajukPredicates.AgePredicate(ConfigurationManager.getInt(CONF_OPTIONS_NOVELTIES_AGE)));
allows to iterate only on items of given age.
- New predicates should be centralized into the JajukPredicates class
Accessing to configuration files
- Since 1.4, the Jajuk workspace (the directory where Jajuk stores all configuration files and indexes) is variable (by default ~/.jajuk in production and ~/.jajuk_test_<version> in developement mode - ie using the -test option). This is why you have to access configuration files this way:
File fConfig = Util.getConfFileByPath(FILE_xxx);
and not trying to build the file path by your own
Design patterns
Singleton [GOF]
- Some Jajuk classes (mainly in org.jajuk.base) are singletons, most of the time for serious reasons.
- Please avoid making a class a singleton if you have no good reason for that
Observer [GOF]
- Jajuk provides a full featured observer pattern implementation (supports details, is fully asynchronous, has a cache, an overflow controler etc..)
- To register to events, a view has to implement Observer interface and provide a list of observed events this way:
public Set<JajukEvents> getRegistrationKeys() {
HashSet<EventSubject> eventSubjectSet = new HashSet<JajukEvents>();
eventSubjectSet.add(JajukEvents.EVENT_DEVICE_MOUNT);
eventSubjectSet.add(JajukEvents.EVENT_DEVICE_UNMOUNT);
return eventSubjectSet;
}
- To handle events, look at this sample :
public void update(JajukEvent event) {
JajukEvents subject = event.getSubject();
if (JajukEvents.EVENT_DEVICE_MOUNT.equals(subject)) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Util.waiting();
refreshDevices();
Util.stopWaiting();
}
});
}
- To notify an event :
ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_MOUNT));
- If you want to make sure that a observer is updated before others, implements HighPriorityObserver instead of Observer (of course, you can set only a single high priority observer per subject).
- IMPORTANT : do not notify more than a single event for one action (for performances and to avoid difficult concurrency issues in views that registrated all these events, we cannot ensure events ordering)
Developers Howto
- Read also the developers howto
- and the Developers Traps



