Picasso and Keycloak

Posted By Hoyt Summers Pittman

So over the weekend I was trying to use Picasso to cleanly load images served by a server secured using KeyCloak. This was surprisingly easy using AeroGear’s authz library.

I needed the following dependencies in my apps build.gradle file

    //AGDroid deps
    compile 'org.jboss.aerogear:aerogear-android-core:2.1.0'
    compile 'org.jboss.aerogear:aerogear-android-security:2.1.0'
    compile 'org.jboss.aerogear:aerogear-android-store:2.1.0'
    compile 'org.jboss.aerogear:aerogear-android-authz:2.1.0'
    //Picasso deps
    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.squareup.okhttp:okhttp:2.4.+'
    compile 'com.squareup.okio:okio:1.5.0'

And I configure Picasso with the following

OkHttpClient picassoClient = new OkHttpClient();

        picassoClient.interceptors().add(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                ModuleFields fields = AuthorizationManager.getModule("KeyCloakAuthz").loadModule(null, null, null);
                Pair<String, String> header = fields.getHeaders().get(0);
                Request newRequest = chain.request().newBuilder()
                        .addHeader(header.first, header.second)
                        .build();
                return chain.proceed(newRequest);
            }
        });

        picasso = new Picasso.Builder(appContext).downloader(new OkHttpDownloader(picassoClient)).build();

*KeyCloakAuthz* is a AuthzModule protecting my server. You can find out more about them on the AeroGear website.

Jul 8th, 2015

Aerogear Android 2.1 Released

Posted By Hoyt Summers Pittman

AeroGear 2.1

What’s New

Sync Alpha

AeroGear has released the first alpha of our data sync technology. This includes the AeroGear Sync Server and libraries for iOS, JavaScript, and of course Android. This technology allows for cross platform data synchronization as seen here :

AeroGear SyncDemo from Christos Vasilakis on Vimeo.

If you followed the development of the Android library you will remember that we originally tried to use Google’s XMPP services as the medium for data sync. Because of technical limitations we dropped this idea and moved to wrapping the Netty client provided with AeroGear Sync Server in an Android service instead.

To activate the service you need to add it to you AndroidManifest.xml file. You will also need to provide properties for serverHost, serverPort, and serverPath. These properties are defined by where you have deployed the sync server. Here is an example connecting to the sync server running on the host of an emulated Android device:

 <service android:name="org.jboss.aerogear.android.sync.SyncService">
  <meta -data
  android:name="serverHost"
  android:value="10.0.2.2" />
  <meta -data
  android:name="serverPort"
  android:value="7777" />
  <meta -data
  android:name="serverPath"
  android:value="/sync" />
</service>

Any Activty you want to receive sync events needs to implement the SyncServerConnectionListener interface, bind itself to the SyncService instance, and then subscribe to events on connections.

Binding and subscribing example :

@Override
protected void onStart() {
 super.onStart();
 serviceConnection = new ServiceConnection() {

  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   final SyncService syncService = ((SyncService.SyncServiceBinder) service).getService();
   SyncActivity.this.service = syncService;
   syncService.subscribe(SyncActivity.this);
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {
   finish();
  }
 };
}

@Override
protected void onResume() {
 super.onResume();
 Intent syncServiceIntent = new Intent(this, SyncService.class);
 bindService(syncServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}

SyncServerConnectionListener implementation Example :

@Override
//Called when the SyncService instance is connected to the Sync server AND the Activity is subscribe to the service after binding.
public void onConnected() {
 /*clientId is a unique identifier which identifies the device connection*/
 clientId = getSyncService().getClientId();

 /*a client document is a document the sync APIs know how to synchronize and is managed by the sync libraries*/ 
 final ClientDocument<jsonnode> clientDocument = clientDoc(documentId, clientId, JsonUtil.toJsonNode(content));

 /*adding a document to the service causes it to send and receive updates*/
 getSyncService().addDocument(clientDocument);
}

@Override
//Called when the document is updated by an external source
public void patched(final ClientDocument data) {
 runOnUiThread(new Runnable() {
  @Override
  public void run() {
   final ClientDocument</jsonnode><jsonnode> document = (ClientDocument</jsonnode><jsonnode>) data;
   final Info updates = JsonUtil.fromJsonNode(document.content());
   //handle your updates here.
  }
 });
}

For a full implementation demo look at our cookbook.

Minor Changes

Pipe improvements

After nearly two years we have implemented AGDROID-7 by adding Pipe.read(String id, Callback<t> callback). Now fetching by id is as simple as the following:

private void retrieveData() {
  LoaderPipe<data> pipe = application.getPipe(this);
  pipe.reset();
  pipe.read(String.valueOf(15), new MyCallback());
}

GCM Push Configuration

We’ve added some extra validation to the GCM Push Registrar. Now if you leave off properties such as variantId the library will throw an exception when you try to build the PushRegistrar as opposed to the registration method failing with an error callback.

GCM Unregistration

Now the library will check to see if you have a registered client before it attempts unregistration. Previously it would always make a call to the Push Server which would fail with a HTTP 404 error if you were not registered. Now the method immediately fails without a network call.

Demo Improvements

We’ve added a few demos to the official cookbook.
* Sync Demo This is the demo for our sync libraries.
* Two Factor This is an example of a Two-Factor One Time Password app using AeroGear.
* Password Manager This demonstrates using encryption to secure a password store behind a passcode.

We’ve also fixed some bugs in the Shoot and Share app as well as the AGReddit app.

What’s Next

For 2.2 and the future we are looking at improvements to our authz libraries as well as better offline resource management. As per usual you can watch our JIRA

About AeroGear

If you would like to learn more about AeroGear’s Android libraries a great place to start is our Android landing page. If you would like to participate in development, have questions, or want to chat with us our community section has all of our contact information.

Changelog

  • AGDROID-362 Migrate AeroDoc example to Gradle and move to cookbook repo
  • AGDROID-156 Update aerogear-crypto-android-demo and move to cookbook repo
  • AGDROID-343 AeroGearGCMPushConfiguration#buildRegistrar needs more validation
  • AGDROID-361 AGReddit should say Bad Password when you fail at logging in.
  • AGDROID-7 add pipe functionality to retrieve data by ID
  • AGDROID-312 Implement Android Client Sync Engine
  • AGDROID-369 Sync Android Demo app
  • AGDROID-313 Implement Android Sync Client
  • AGDROID-368 unregister fails with server returned the error code 405 android
  • AGDROID-385 Update AeroGear Sync README
  • AGDROID-377 Move DiffSync client into a android.app.Service
  • AGDROID-386 Deprecate and remove client-xmpp
  • AGDROID-370 XMPP Client NPE @ DiffSyncClientHandler.java:45
  • AGDROID-364 Package XMPP Sync Client to not include duplicate files
  • AGDROID-363 Refactor XMPP Sync Client to get below the 65k method limit
  • AGDROID-371 XMPP sync client should support json patch
  • AGDROID-367 Shoot-n-Share 401 error (invalid_client) on Google Drive upload
  • AGDROID-366 Shoot-n-Share does not offer keyboard for Keycloak redirected login screen
  • AGDROID-365 XMPP Sync Client does not handle multiple documents correctly
Mar 25th, 2015

Writing a Maven Plugin Unit Test

Posted By Hoyt Summers Pittman

If you are trying to write a Maven plugin with unit tests and following Apache’s Maven documentation you may end up with a dependencies like this :

 <dependencies>
        <dependency>
            <groupid>org.apache.maven</groupid>
            <artifactid>maven-plugin-api</artifactid>
            <version>3.2.5</version>
        </dependency>

        <!-- dependencies to annotations -->
        <dependency>
            <groupid>org.apache.maven.plugin-tools</groupid>
            <artifactid>maven-plugin-annotations</artifactid>
            <version>3.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupid>org.apache.maven.plugin-testing</groupid>
            <artifactid>maven-plugin-testing-harness</artifactid>
            <version>3.2.0</version>
            <scope>test</scope>
            <type>jar</type>
        </dependency>

    </dependencies>

Because that is what their docs say. Their docs are lies straight from the pits of hell. Your dependencies section should look like this :

<dependencies>
        <dependency>
            <groupid>org.apache.maven</groupid>
            <artifactid>maven-core</artifactid>
            <version>3.2.5</version>
        </dependency>
        <dependency>
            <groupid>org.apache.maven</groupid>
            <artifactid>maven-artifact</artifactid>
            <version>3.2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupid>org.apache.maven</groupid>
            <artifactid>maven-compat</artifactid>
            <version>3.2.5</version>
        </dependency>

        <!-- dependencies to annotations -->
        <dependency>
            <groupid>org.apache.maven.plugin-tools</groupid>
            <artifactid>maven-plugin-annotations</artifactid>
            <version>3.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupid>org.apache.maven.plugin-testing</groupid>
            <artifactid>maven-plugin-testing-harness</artifactid>
            <version>3.3.0</version>
            <scope>test</scope>
            <type>jar</type>
        </dependency>
    </dependencies>

I discovered this after trying to debug the following stack trace

Caused by: java.lang.ClassNotFoundException: org.apache.maven.execution.MavenExecutionResult
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 23 more

and only finding a bug in Maven’s tracker marked closed as a duplicate. Duplicate of what? Who knows. Eventually I had to break down to the tried and true method of copying code from a project that works. A big thanks to simpligility and the APL.

Jan 28th, 2015

Another rant on Android Studio

Posted By Hoyt Summers Pittman

There are two types of software in this world, software people complain about and software nobody uses. I use Android Studio and I will murder before going back to Eclipse, but my preferred build system for Android is still Maven. This is not going to change for a very long time because the Gradle integration tooling (IDEs) and the Android Gradle ecosystem aren’t caught up. There are many better tools and plugins which work wonderfully in the Maven ecosystem and fail utterly in the Gradle Ecosystem.

When the correct plugins exist, it is more pleasurable to work in Maven than Gradle full stop. The tooling and autocompletion around Maven is much much better. As a example, I have auto completion for artifacts in my IDE of choice in Maven which is regularly indexed from Central. In Android Studio I do not have this feature. In my preferred IDE, NetBeans, Maven projects are opened unaltered with no weird side effects such as creating dot directories or IDE files. In Android Studio importing an Android Gradle project is like playing roulette. Do I open the project or do I import it? Will Android Studio find my code this time or do I have to close the IDE, delete the directory, re-clone, and try again (an extreme example but this is in comparison to NetBeans where opening always works).

The ecosystem gulf between Maven and Android Gradle is terrifying. Code formatting, license plugins, automated testing harnesses, code coverage reports, etc all JUST WORK with Maven and Android. Android Gradle forks and is incompatible with the Java plugin. This means that every project which exists in Gradle to perform some hideously boring task (i.e. manage license headers) has to be rewritten to include Android support. This doesn’t seem to be happening.

What can Android Studio do to get better? 1) Fix importing code. Don’t leave me with a useless project with just the Gradle view EVER. 2) Don’t drop .iml and .idea directories in my project EVER. 3) Fix auto completion when editing the gradle files. It is REALLY painful right now and trivial tasks (is this still the latest version of this library, is this groupId org.apache.project or org.apache, etc) requires a trip to web browser land instead of an Ctrl+Space to see what is in the drop downs. 4) Make the Android plugin depend on the Java plugin and work correctly with it.

In conclusion, I don’t hate Gradle, I don’t even hate the Android Gradle plugin. I hate the NIH which pervades the Android Gradle plugin and the break from the larger Java ecosystem that it represents.

Jan 26th, 2015
Next Page »