Automating android application signing and zipaligning with maven

This is something that has had me tearing my hair out for a few days now, I was pretty much border-line braveheart-ing my screen….

Code rage

I’ve recently been on a little drive to try to maven-ize my projects. All had been going well until I needed to sign and zipalign my APKs. This post will help you conquer that barrier with the use of some maven plugins.

When using ant, I was able to simply enter keystore details into build.properties and just call “ant release”. Unfortunately that approach doesn’t carry across to maven, and you have to provide some more configuration.

Firstly, before we go any further, I’m going to assume that you already have a maven android project setup, so you have a pom.xml, you’ve configured the maven-android-plugin and you can run “mvn clean install” to build your APK, and “mvn android:deploy” to deploy it to an emulator. If you haven’t got that far, I’d suggest you have a look at one of my previous posts to help get you up to speed.

So, when you want to build your application with maven, you’d run “mvn install”. That will, by default, use a debug key to sign your APK. When we want to build a releasable APK we still want to execute the same install goal, however we’ll want to use a proper key. Luckily, maven provides something called profiles.

In short, maven profiles allow you to still perform the same standard goals, yet they behave slightly different, in the manner of binding extra steps to them, all will come clearer in a moment.

This has already been covered, in a useful post by the guys at Novoda, and various other blog posts scattered around the web. I’ve followed at least 10 tutorials and each time I was unable to get the signing process to work correctly, each time I encountered the following error :

INFO] jarsigner: attempt to rename C:\android-projects\jameselsey_andsam_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar to C:\android-projects\jameselsey_ands
am_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar.orig failed
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed executing 'cmd.exe /X /C "C:\development\tools\Java\jdk1.6.0_20\jre\..\bin\jarsigner.exe -verbose -keystore my-release-key.keystore -storepass '*****' -keypass '
*****' C:\android-projects\jameselsey_andsam_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar mykeystore"' - exitcode 1
[INFO] ------------------------------------------------------------------------

I’d tried everything, even copying out the command and pasting into a command window worked, but I could not get it to work from maven. Unfortunately it seems there may be an issue with the maven-jarsigner-plugin (as suggested in the comments on the Novoda post). However fear not, for there is an alternative, the maven-jar-plugin.

The maven-jar-plugin is a similar plugin to the jarsigner plugin, however the signing APIs are now deprecated and it points you to use the (apparently) broken maven-jarsigner-plugin. Using a deprecated API doesn’t particulary concern me in this instance, as its just signing artefacts.

Take a look at my profiles section, copy this into your pom.xml :

<profiles>
<profile><!-- release profile. uses keystore defined in keystore.* properties. signs and zipaligns the app to the target folder-->
            <id>release</id>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
            <build>
                <defaultGoal>install</defaultGoal>
                <finalName>${project.artifactId}-${project.version}</finalName>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-jar-plugin</artifactId>
                        <version>2.2</version>
                        <executions>
                            <execution>
                                <id>signing</id>
                                <goals>
                                    <goal>sign</goal>
                                </goals>
                                <phase>package</phase>
                                <inherited>true</inherited>

                                <configuration>
                                    <keystore>
                                        my-release-key.keystore
                                    </keystore>
                                    <storepass>mypassword</storepass>
                                    <keypass>mypassword</keypass>
                                    <alias>mykeystore</alias>
                                    <verbose>true</verbose>
                                    <verify>true</verify>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>

                    <plugin>
                        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                        <artifactId>maven-android-plugin</artifactId>
                        <inherited>true</inherited>
                        <configuration>
                            <sign>
                                <debug>false</debug>
                            </sign>
                        </configuration>
                    </plugin>

                    <plugin>
                        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                        <artifactId>maven-android-plugin</artifactId>
                        <configuration>
                            <zipalign>
                                <verbose>true</verbose>
                                <skip>false</skip>
                                <!-- defaults to true -->
                                <inputApk>${project.build.directory}/${project.artifactId}-${project.version}.apk</inputApk>
                                <outputApk>${project.build.directory}/${project.artifactId}-${project.version}-RELEASE.apk
                                </outputApk>
                            </zipalign>

                        </configuration>
                        <executions>
                            <execution>
                                <id>zipalign</id>
                                <phase>install</phase>
                                <goals>
                                    <goal>zipalign</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
</profiles>

OK, so lets walk through what the above profile does. Firstly, the “id” of the profile is “release”, so when you want to apply this profile, you’d run “mvn install -Prelease”. The “activeByDefault” is set to false, which means you need to use the above arguement, if you flip that over, you won’t need the P flag.

The execution goal is to “sign”, which is the API on the plugin, documented here. We bind this execution on to the standard “package” goal. Then we provide the configuration elements which specify the details of the keystore.

In pure English, this binds the plugin phase onto the package goal of maven, so anytime we run using this profile it’ll execute the jar signing of our artefacts. The “verify” tag gives us extra piece of mind by verifying that the signing was successful afterwards.

I’ve also setup a zipalign profile that will take the APK, zipalign it, and rename it to “*-RELEASE.apk”, so I know that particular APK is the one which I’ll release to market.

So thats it, once more a success, and its just one small step on the ladder to android glory!

Phhew!! Done, finally I was able to shutdown the laptop and go to sleep at 3am….on a school night!!!

Good luck, feel free to comment!

Peace.

String concatenation operator

The string concatenation operator is a bit like a hedgehog, it looks cute and sweet, but try to grab hold of it quickly and you’ll soon know about it…

It’s actually quite simple, however there are some traps that are very easily overlooked (just got caught out with it on a mock test, so I’m here to rant).

The rule of thumb is, that if either one of the operands being “+” is a String, then concatenation will occur, but if they are both numbers, arithmetic addition will occur. Sounds simple right? What do you think the following equate to?

package operators;
public class MockTest
{
    public static void main(String[] args)
    {
        System.out.println(3 + 2);
        System.out.println(3 + "s");
        System.out.println("s" + 2);
        System.out.println("hello " + "world");
    }
}

Think you know it? Well its going to be : 5, 3s, s2. The first one is an arithmetic addition, since both sides of the operator are numeric. The second and third are String concatenation, because at least one of them is a String. The fourth one are both Strings, so concatenation once again.

those are the simple ones, however it can get a lot more tricky, have a look at these common ones that those exam creators try to catch you with!

package operators;

public class MockTest
{
    public static void main(String[] args)
    {
        // Inside brackets are evaluated first, so it'll be 7String
        System.out.println( (3 + 4) + "String");

        /* This is the little bugger that caught me, I vouched for 34String, but its actually 7String.
         Concatenation happens from left to right, one at a time, so it'll break it down to:
            3 + 4 then...
            <thing on left> + "String"

         Careful on these ones!
        */
        System.out.println(3 + 4 + "String");

    }
}


So remember, it’ll evaluate from left to right, one “+” operator at a time. Brackets are always evaluated first however.

Take my examples and have a play!

Happy coding (or raging at the screen if the mock tests catch you out…)

The instanceof Operator

The instanceof operator is a great way for checking if a reference variable is of a given type, in other words, does it pass the IS-A inheritance test. Ask yourself, is a Cat a Dog? A Dog a Cat? Or is a Cat an Animal and a Dog an Animal? In true Harry Hill style, there is only one way to decide….FIGHT!!!!

Have a look at my following example :

package operators;

public class InstanceOfOperatorDemo
{
    public static String myString = "James";

    public static void main(String[] args)
    {
        // myString variable is of type String, so returns true
        System.out.println("myString instanceof String : " + (myString instanceof String));
        // Even though myString is a String, a String is actually an Object (extends from Object), so the below is also true
        System.out.println("myString instanceof Object : " + (myString instanceof Object));

        B b = new B();
        // B is technically an instance of the implemented interface, so this should return true
        System.out.println("B instance of Foo : " + (b instanceof Foo));
        // This should return true also for the same reasons as above
        System.out.println("A new A() instance of Foo : " + (new A() instanceof Foo));
        // An A isn't an instance of a B, its the other way around; a B IS-A A, so returns false
        System.out.println("A new A() instance of B : " + (new A() instanceof B));

        // Any checks with null always return false, since null isn't an instance of anything
        System.out.println("null instanceof Object : " + (null instanceof Object));

        int[] myInts = new int[10];
        // Even though this array contains primitives, the array itself is still an Object at heart..
        System.out.println("myInts instanceof Object : " + (myInts instanceof Object));
    }
}

interface Foo {}
class A implements Foo {}
class B extends A {}

As we can see, a String IS-A Object, so that will pass the instanceof test. It is also important to note, that interfaces are also included in the instanceof check, so by checking if a class or a subclass is an instanceof an interface will return true.

Arrays, no matter what they hold, are always objects themselves, so they can be checked for instanceof too, of which they are Objects, as shown above.

It is important to note, that you can’t use instanceof across class hierarchies, this is something they’ll try to trick you out of in the exam, such as comparing a cat against a dog, you can compare up the hierarchy, but not across it, have a look at this example :

package operators;

public class InstanceOfOperatorCrossHierarchyDemo
{
    public static void main(String[] args)
    {
        // a Cat IS-A Dog, plain and simple
        System.out.println("Is cat an instanceof Animal? : " + (new Cat() instanceof Animal));

        // This will fail to compile, since we are not allowed to instanceof check across the
        // object hierarchy, a Cat is not an instance of Dog, so compiler fails
        System.out.println("Is cat an instanceof Dog? : " + (new Cat() instanceof Dog));
    }
}

class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

That’s it! A nice and easy one, please leave me comments if you can suggest improvements!

Happy coding.

Compound Assignment Operators

There are various compound assignment operators, however it is only necessary to know the 4 basic compound assignment operators for the exam, being as follows:

  1. += (Addition compound)
  2. -= (Subtraction compound)
  3. *= (Multiplication compound)
  4. /= (Division compound)

Essentially, they’re just a lazy way for developers to cut down on a few key strokes when typing their assignments. Consider the following examples that I’ve created to demonstrate this:

package operators;

public class AssignmentsOperator
{
    public static void main(String[] args)
    {
        int x = 5;

        // This is the "longhand" way of adding 5 to x
        x = x + 5;
        // You could use the compound assingment as follows, to achieve the same outcome
        x += 5;


        // Lets look at the other 3...
        // This...
        x = x - 1;
        // ...is the same as
        x -= 1;

        // This...
        x = x * 10;
        // ...is the same as
        x *= 10;

        // This...
        x = x / 10;
        // ...is the same as
        x /= 10;

    }
}

That is it! Any suggestions, please let me know!

Happy coding.

Static members…

Statics are a rather strange beast, they belong to no instance of a class, they have no fixed abode, other than their class..

Consider the following example :

package declarations;

public class StaticMembers
{
    private static String message = "hello";
    private String instanceMessage = "hello from the instance!";
    
    
    public static void main(String[] args)
    {
        // You "can" create a new instances and call the static member, but its a bit redundant....
        StaticMembers staticMembers = new StaticMembers();
        System.out.println(staticMembers.message);

        // ..Since you can just call it directly, as statics don't belong to any instances
        System.out.println(StaticMembers.message);
        
        // You can't do this, since how would the static know which "copy" of the instance method to get?
        System.out.println(instanceMessage);
        
        // ..But you can do this, since you have an instance..
        System.out.println(staticMembers.instanceMessage);
        
    }
}

Statics don’t belong to any instance, they belong to the class itself. So there is only ever one copy of a static member (method or variable). Statics can’t ever access an instance variable directly, why not? Think about it, if a static wants to obtain an instance member variable, there may be hundreds, how would it know which one to get? You can however, declare and initialise an instance member from a static, and then access its members, as we’ve done in the example above.

Take my example, and have a play with it, statics are actually quite straightforward once you understand how they behave, but be careful, the exam will try and trick you out with statics accessing instance members directly!

Happy coding!

Local Variables, as far as the SCJP is concerned

Local variables are variables that are declared locally, funny that eh? This one should be nice and easy, lets have a look at a quick example :

package scope.localvariables;

public class LocalVariables
{
    private String instanceString;

    public void doSomething()
    {
        // local variable called 'localS', initialised
        String localS = "hello";
        // Another initialised local variable, with the final modifier so it can't be changed once initialised
        final String localS2 = "hello again";

        localS = "I've changed, since I'm not final";

        System.out.println(localS);
        System.out.println(localS2);
    }

    public void doSomethingElse()
    {
        String localS;
        // Compiler won't like this, since you haven't initialised 's' with anything
        System.out.println(localS);
    }
}

Some really easy things to remember, local variables don’t ever get initialised automatically, so you have to do that yourself. The method above, doSomethingElse, the variable gets declared, but never assigned a value. The compiler won’t assign a default value like it does for an instance varible, so the compiler will complain on the line which tries to print the value to system out. So whatever you do, if you declare a local variable but don’t assign it a value, make sure that you DO assign it a value before you try to use it.

Since variables are declared within a method, they can only be accessed, and actually only live for the duration that method is executing. So if you declare a variable inside a method, but try to access it elsewhere, your code will fail to compile since its scope is only available to the method the declaration resides in. Careful of this one, there are a lot of questions in the exam which will try to catch you out with this!

Local variables can take the final modifier if required, so that once assigned a value it can’t be changed.

Also note, that local variables live on the stack, and not the heap.

Lastly, it is possible to have local variables with the same names as instance variables, this is known as shadowing. You’ve probably seen this countless times before without actually realising, since its quite popular with constructors (with may also have local variables)

package scope.localvariables;

public class MyClass
{
    private String name;
    private int age;

    // Overridden constructor, with 2 local variables that shadow instance variables
    public MyClass(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public static void main(String[] args)
    {
        MyClass myClass = new MyClass("James", 25);
        System.out.println("Name is : " + myClass.name + " Age is : " + myClass.age);
    }
}

Thats it, hope you’ve enjoyed the show folks, please leave comments or improvement suggestions!

Thanks!

Other modifiers, for members…

We’ve already touched upon various modifiers, for classes (both access and non-access), but there are also some more modifiers for members, as detailed here.

We have the following modifiers for members :

  • final – Can’t be overridden
  • abstract – No implementation specified, subclass must implement
  • synchronized – Only a single thread of execution can pass through at a given time
  • native – Implemented by a 3rd party piece of code (C++ for example)
  • strictfp – Enforces foating point precision and doesn’t let the JVM do its own way

To make things easier, you don’t actually need to know how the strictfp or native work for the exam, but you’ll need to be aware of them. Strictfp guarantees precision on floating point calculations (otherwise the JVM implements precision however it feels), and the native is used for external implementations, such as implementing methods in C++.
All you must remember with these, is that the native modifier applies only to methods, but the strictfp modifier applies to both classes and methods. So lets have a look at a brief example then pass aside on these two and focus on the ones that matter.

package modifiers;

// The class can be marked as strictfp too!
public strictfp class NativeAndStrictfp
{
    // A normal method
    public String giveMeAString()
    {
        return "hello";
    }
    
    // strictfp method
    public float giveMeAFloat()
    {
        return 123.123f;
    }
    
    // pretend its abstract, we don't provide implementation so use a semi colon not braces!
    public native String doSomeNativeCodingAndReturnAString();
}

As with classes, the final modifier does the same thing, it states that the particular method can’t ever be overridden in a subclass, simple as that.

The same applies to the abstract modifier, abstract methods are declared with a signature, a return type, an optional throws clause, but are not actually implemented. The first concrete subclass to extend from the class has to override that method and provide its implementation.

Consider the following example :

package modifiers;

// Don't forget, that since we have one abstract method, the whole class must be marked abstract!
public abstract class OtherMemberModifiers
{
    // I'll get inherited, since I'm public, but I can't be overridden.
    public final String giveMeAString()
    {
        return "hello";
    }

    // Remember, semi colon, no braces!!
    public abstract String giveMeAnotherString();
}

class ClassThatExtends extends OtherMemberModifiers
{
    // I'm the overridden abstract method above!
    @Override
    public String giveMeAnotherString()
    {
        return "another string";
    }
}

Remember, abstract methods can’t be private or final, otherwise how would it ever be overridden? Think about it!

Lets cover the synchronized modifiers. Synchronized means that only one thread of execution can pass through that method at a given time, and you can use the modifier just like any other, they can also be marked as final, to prevent subclasses from overriding your implementation. Lets have a look :

package modifiers;


public class SyncModifiers
{
    // Just a synchronized method ;)
    public synchronized String giveMeAString()
    {
        return "hello";
    }

    // I can't be overridden by a subclass
    public final synchronized String giveMeAnotherString()
    {
        return "hello again!";
    }
}

The synchronized modifier can also be used on code blocks, but we’ll cover that more in the threading posts.

Well thats it! I hope I’ve explained things well, if you find any mistakes or want to suggest improvements, please let me know!

Happy coding!

Class Modifiers (non-access)

In addition to class access modifiers, classes can also be marked with non-access modifiers. These modifiers imply rules on a class, but are not necessarily linked to access rights.

The following non-access modifiers are available:

  • final – The class can’t be extended.
  • abstract – The class has to be extended, and can’t be instantiated on its own.
  • strictfp – Ensures that you always get exactly the same results from your floating point calculations on every platform your application runs on. If you don’t use strictfp, the JVM implementation is free to use extra precision where available.

Lets make things easier, its worth knowing what strictfp is, but its not on the SCJP exam so you don’t need to know how to use it, so you can almost brush that aside after remembering the information above.

Final classes can’t be extended / subclassed. Thats great, for those times when you don’t want people extending your classes, mark them private. Take the String class for example, that is private, as they didn’t want developers extending it and altering the way Strings behave, that would cause nightmares for all sorts of applications!

The other non-access modifier is the abstract modifier. There may be times when you don’t want people to instantiate your class. Say that you had a class Car, but you didn’t want people to start creating Car objects all over the place, you want them to extend your Car class and create their own functionality, you might choose to make Car abstract, like the following example:

package declarations;

public abstract class Car
{
    public void doSomething()
    {
        
    }
}

class SportsCar extends Car
{
    public static void main(String[] args)
    {
        // do SportsCar stuff here
    }
}

Don’t forget, that a class can’t be both final and abstract, as the contradict each other, one can’t be subclassed, yet the other must be subclassed, it just won’t work!

We’ll touch more upon abstract classes in the interfaces sections, as interfaces are essentially 100% abstract classes, but more about that later :)

Class Access Modifiers

Class access modifiers define who can see the class, you use it on a daily basis, have a look at the following :

public class ClassAccessModifierExample
{
    public static void main(String[] args)
    {
        // do something!
    }
}

There you go, you said “public class”, thats you saying that this class is public, and anything can access it.

It is important to note, that even though a class may be declared as public, you can still have private members within that class. The class access modifier merely states who can gain access to the class.

There are 3 class access modifiers, in other words there are 3 keywords that you can use :

  1. public – any class can import and use your class.
  2. protected – any class in the same package as yours can import and use your class, additionally, any class that resides in another package, can extend and use your class. This is only really useful for inner classes.
  3. private – no other top level class can import and use your class. This is a bit of an odd situation but is useful for inner classes, detailed in another post.

Those are your 3 keywords, however there is actually a 4 level of access, called default. The default access level doesn’t use a keywork, so it would be used like follows :

class ClassAccessModifierExample
{
    public static void main(String[] args)
    {
        // do something!
    }
}

So our 4th access level is :

  • (default) – also called “package-private”, this class is only visible to classes in the same package.

So what is all the fuss about visibility about? Well it lets classes do various things,such as :

  1. Create an instance of the class
  2. Extend, sublass that class
  3. Access members of that class

One last thing to remember, is that a source file can only ever have one public or default class, it can’t have more than one of those. Also, private and protected can’t be at the top level.

  • You can’t have a private top level class, its useless.
  • You can’t have a protected top level class, since it goes against the principle of the protected access.

Consider the following valid example

// I'm public, and my name matches that of the source file
public class ClassAccessModifierExample
{
    public static void main(String[] args)
    {
        // do something!
    }


    // You can have as many protected classes as you want, accessible
    // to any classes that extend from the top level class, ClassAccessModifierExample
    protected class MyProtectedClass
    {

    }

    // Have as many private classes as you want, they are only accessible to the top level class,
    // ClassAccessModifierExample
    private class InnerClassThatIsPrivate
    {

    }
    
    // Nothing wrong with having a public inner either!
    public class PublicInner
    {
        
    }
}
// Default class here
class TopLevelDefaultClass
{

}

Thats it! If you’ve got any suggestions on how to improve this, please leave a comment :)

Coupling and Cohesion, what you need to know for SCJP…

Coupling and cohesion are two terms that often get mixed up, however they are actually really simple concepts, and the bonus is, they don’t just apply to Java.

Coupling

Coupling, in its purest terms, means “the degree to which one class knows about another class”. If one class uses another class, that is coupling. Coupling is everywhere, but the level of coupling varies.

Consider the following example of a tightly coupled set of classes:

public class TightlyCoupledClass
{
    public static void main(String[] args)
    {
        ExampleClass exampleClass = new ExampleClass();
        exampleClass.message += "James";
        System.out.println(exampleClass.message);
    }
}

class ExampleClass
{
    public String message = "hello ";
}

TightlyCoupledClassuses ExampleClass, therefore there is some coupling. The level of coupling is high as TightlyCoupledClassdirectly alters the message variable on ExampleClass. It’ll compile and run perfectly fine, but if you slip this little nugget into production code, you’re colleagues will bash you for eternity, because its poor design.

Think of it this way, what if ExampleClass was used in hundreds of classes, or what if ExampleClass was maintained by someone else; what would happen if they decide to change the scope of message, or to change its data type? It’ll break anything that uses it, since it is tightly coupled.

From the perspective of TightlyCoupledClass, it needs to get a message, and set a message, it should not care about how ExampleClass maintains that. When a class knows too much about another classes’ implementation, that is also tight coupling.

What we need, is encapsulation, this is another OO concept that shields a classes state and exposes it with accessor methods, meaning that a class can still be coupled, but loosely.

You should, be aiming for loosely coupled classes, lets re-visit the above sample but this time we’ll move from a tightly coupled set of classes, to a loosely coupled set of classes, using encapsulation.

public class TightlyCoupledClass
{
    public static void main(String[] args)
    {
        ExampleClass exampleClass = new ExampleClass();
        String ourUpdatedMessage = exampleClass.getMessage() + "James";
        exampleClass.setMessage(ourUpdatedMessage);
        System.out.println(exampleClass.getMessage());
    }
}

class ExampleClass
{
    private String message = "hello ";

    public String getMessage()
    {
        return message;
    }

    public void setMessage(String message)
    {
        this.message = message;
    }
}

Cohesion

Cohesion is another OO concept like coupling, however cohesion refers to the degree in which a class has a single, well defined purpose. If you had a class called Car, it would maintain state such as numberOfWindows, numberOfWheels, and have behaviour (methods) such as drive(), brake(), stop() etc. That would indicate that the class is cohesive, meaning that it serves a single, defined purpose.

Now, exploring a little, if the Car class suddenly decided to have methods such as switchOnTheTV(), or hangTheWashingOut(), then its not really doing Car-like behaviour. If a class is trying to do more than one thing, it is considered a low cohesive class.

Consider the following, highly cohesive class

package ooconcepts;

public class Car
{
    private String make = "Aston Martin";
    private int numberOfWindows = 5;
    
    public void drive()
    {
        // do some driving!
    }
    
    public void brake()
    {
        // slow down!
    }
    
    public void stop()
    {
        // STOP!!!!
    }      
}

Conclusion

These are the important bullet points to take away from this page:

  • Coupling refers to the degree in which one class knows about another, or makes use of another classes’ members
  • Loose coupling is GOOD as classes are well encapsulated to minimise references to each other
  • Tight coupling is BAD because a class shouldn’t know about the workings of another
  • Cohesion refers to the degree in which a class has a single, well defined purpose
  • High cohesion is GOOD as a class does only what it should
  • Low cohesion is BAD because a class is trying to solve everything and not just its specific purposes

Further Reading

  1. Why couplig is always bad
  2. Java Boutique