Jajuk Advanced Jukebox

Follow us on GitHub

Developer guide

Source Code Management

See the Git page.

Building the code

Requirements

Building from the source package distribution

See the instructions in BUILD.txt.

Building from the Github checkout

Checkout the code from Github and simply run the following to compile the code locally

ant -Dbasedir=`pwd` -f ./src/packaging/ant/build_enduser.xml

Developers mailing Lists

Java version

IDE

We recommend the Eclipse platform. All following documentation is applicable to Eclipse only. We use basically Eclipse built-in formater configuration with :

To launch jajuk from Eclipse, create a run configuration with :

  • -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) .
  • Code conventions

    Eclipse formatter and templates

    String externalization

    XML

    Comments

    Dead code

    Please remove any dead code, SCM helps to recover any previous code anyway. Tip : install the http://www.ucdetector.org eclipse plugin.

    Class headers

    Code quality

    Please keep Eclipse standard level of warnings (imports, static context…) and make sure to cleanup imports (Control-Alt-o). Check the Sonar analysis, you may want to install the local Sonar plugin as well.

    GUI threading conventions

    Documentation

    Layout Manager

    Validation

    Wizards

    Unit Testing

    General Guidelines

    The following guidelines should be observed when committing code changes:

    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:

       // helper method to emma-coverage of the unused constructor
       public void testPrivateConstructor() throws Exception {
         JUnitHelpers.executePrivateConstructor([yourclass].class); 
       }

    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

    Development hits and available features

    Guava

    We use 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

    Log.debug("Search URL: {{" + sURL + "}}");

    Utilities features

    Files filters

    new JajukFilter(false,JajukFileFilter.DirectoryFilter.getInstance(),
       JajukFileFilter.AudioFilter.getInstance());

    Collection filters

    Iterator it = new FilterIterator(tracks.iterator(),
      new JajukPredicates.AgePredicate(ConfigurationManager.getInt(CONF_OPTIONS_NOVELTIES_AGE)));

    allows to iterate only on items of given age.

    Accessing to configuration files

    File fConfig = Util.getConfFileByPath(FILE_xxx);

    and not trying to build the file path on your own

    Design patterns

    Singleton [GOF]
    Observer [GOF]
    public Set<JajukEvents> getRegistrationKeys() {
      HashSet<EventSubject> eventSubjectSet = new HashSet<JajukEvents>();
      eventSubjectSet.add(JajukEvents.EVENT_DEVICE_MOUNT);
      eventSubjectSet.add(JajukEvents.EVENT_DEVICE_UNMOUNT);
      return eventSubjectSet;
    }
    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();
        }
      });
    }
    ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_MOUNT));
    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)

    D-Bus

    See these archives

    Howtos

    How to get tracks for a given artist, album, year or genre ?

    TrackManager.getAssociatedTracks()

    How to get playable files for any item (logical or physical)?

    Util.getPlayableFiles()

    How to filter a list of items ?

    Filter.filterItems(<list>,<property name>,<value>)

    How to get the number of items (track, files…) ?

    [item type]Manager.getInstance().getElementCount()

    How to add a new option ?

    public static final String CONF_AUDIOSCROBBLER_ENABLE = "jajuk.network.audioscrobbler"; 
    properties.put(CONF_AUDIOSCROBBLER_ENABLE, FALSE);

    How are managed window startup sizes and positions ?

    begin
     width = screen width
     if width > 1400  
       width = 1200  //deal with dual heads
     else
       width = screen width - 120
     height = screen height
     if height > 1200  
      height = 1000  //deal with dual heads
     else
      height = screen height - 120
    end
    
    begin
     if we find a forced position in conf.properties (jajuk.frame.forced_position entry)
      use this position/size (used to allow XGL users to force a position)
     else
      if window manager buggy
        Apply (60,60,screen width - 120, screen height - 120)
      else 
        if stored position (jajuk.window_position) contains "max" (maximalize)
          if window manager supports expand
          	expand (the window manager then deal with task bars)
          else
       	Apply (60,60,screen width - 120, screen height - 120)
        else
         int x = configurated x
         int y = configurated y
         int width = configurated width
         int height = configurated height
         if x < 0 or x > screen width
          x = 60
         if y < 0 or y > screen height
          y = 60
         if width <= 0 or width > screen width
          width = window width - 120
         if height <= 0 or height > screen height 
          height = screen height - 120
         Apply (x,y,width,height)
    end
    

    How to manage mouse events and right clicks ?

    How to use the font manager ?

    FontManager.getInstance().getFont(<a JajukFont>)

    How to format dates ?

    How to get good random value ?

    UtilSystem.getRandom()

    Traps

    Date format not thread safe

    canWrite() method

    SteppedComboBox fonts

    Reading events properties

    Trailing zeros

    Do not use trailing 0 in integers like in :

    throw new JajukException(005);

    but instead :

    throw new JajukException(5);

    because 005 != 5 (octal)

    Char issue

    Avoid using chars in strings building because a char + int + string => (int) + string. Example:

    String s = '('+33+") foo)"

    How to avoid memory leaks ?