Posts tagged 'asf'



Roller 6 released

This latest release of Roller includes a new UI that uses Twitter Bootstrap 3 and is based on work I started in 2015 and first committed on December 21, 2015 with this commit: 2da6c3c2e28419f68244e0c362c15be96013d5f9. You can find the details on on the Roller project blog. I got lot of help along the way with testing, fixes, dependency upgrades, Java 11 support and more, so thanks to all that helped make this happen.


Powered by Digital Ocean Kubernetes

Just a note to say that I've switched this site over to Digital Ocean Kubernetes service, which is in Limited Availability right now.

Digital Ocean's Kubernetes service is just as simple and well designed as the rest of Digital Ocean. I mentioned before that I rolled my own Kubernetes cluster via Ansible and Kubeadm. Now I can delete all those config files and that's a good thing. Plus, the price is right; I can get by with one $10/month node (1 CPU / 2 GB memory) and a $10/month load balancer.

To get this site up and running I had to deploy four things to my cluster. I installed the NGINX Ingress Controller, Cert-Manager for automatic creation of Let's Encrypt TLS certs, PostgreSQL and my custom build of Apache Roller. All of that went pretty smoothly and I didn't run into and problems that I could blame on Digital Ocean.


Roller 6.0.0-SNAPSHOT

Upgraded this site to Roller 6.0.0-SNAPSHOT today, which meant an hour of fiddling around with my private Docker registry, then giving up and using the one free private repository offered by DockerHub and then, another hour of futzing around trying to figure out my PostgreSQL JDBC driver doesn't work anymore (I inadvertently upgraded from JDK 1.7 to 1.8) and why I can't seem to upgrade it (Kubernetes caches Docker images unless you set imagePullPolicy to always). In the end, I got it working. This post is written in the yet to be officially release Apache Roller 6.0.0-SNAPSHOT version.

Side note: the new rich-text editor in Roller is now Summernote and it seems quite nice. I need to tweak it a bit because there is currently no way to set the font or add a link unless you switch to raw HTML mode.


Roller's new web UI

About three years ago I decided to modernize and improve the Apache Roller web UI by rewriting the JSP pages to use the Struts 2 Bootstrap tags, which use Twitter's Bootstrap v3 components and JavaScipt. I also wanted to replace all the HTML table-based formatting with div's and Bootstrap, do a bunch of other improvements and make Roller's web UI less clunky and annoying.

Converting Roller's eight-five JSP pages was a big task and I did not have much time for it. That's why it took three years. Ironically, the Roller modernization project leaves Roller three years out of date. Still, I think it is a huge improvement over the Roller v5 web UI and I want to get it released in Roller v6. Currently, this work is available as Pull Request #22 and you can find some screenshots there too. Here's one:

screenshot of Roller Edit Entry page

Try it with Docker-Compose

I also did some work to make it super-easy to try the Roller v6 snapshot pre-release for yourself, by using Docker Compose. You don't have to fiddle with Tomcat or PostgreSQL. You can find a simple Dockerfile for running Roller v2 snapshot and a docker-compose.yml file linked below. And you can find a Docker image in my DockerHub repo.

If you want to try Roller v6 snapshot, here's what you need to do:

1 - If you don't aleady have it, install Docker

2 - Create a directory on your computer where you want Roller to store it's data.

3 - Save this file docker-compose.yml to that new directory.

4 - Open a shell in that new directory and run:

docker-compose up

5 - Watch the PostgreSQL and Roller startup logs scroll by

6 - When the log scroll slows go to http://localhost:8080 to access Roller and go through the initial setup.

Alternatively, if you want to try Roller the hard way, you can get the regular-style v6 SNAPSHOT release files here roller/roller-6.0/v6.0.0.

Let us know how it goes

I hope you'll give Roller v6 snapshot a try and let the project know how it can be improved for your use. Send feedback to the Roller mailing lists or ttweet at us at @apache_roller.



Powered by Kubernetes

kubernetes logo Just a quick note to say that I ditched Docker Swarm and now this rarely updated blog is powered by Kubernetes. Total overkill, I know. Like Roller itself, I did it as a learning exercise. I hope to blog more about what I learned by doing this. For now, here's a quick summary of what I've done so far.

Created a cluster

I created a 2-node Kubernetes cluster on Digital Ocean using some hand-crafted Ansible scripts that call apt-get to install and kubeadm to start Kubernetes. I considered using Typhoon to create the cluster, but I really wanted to learn how to install Kubernetes "from scratch".

Ran two Ingress Controllers

To avoid using Digital Ocean's $20/month load balancer I'm running an Nginx Ingress controller on each node, and pinning containers to nodes using labels and nodeSelectors. I had to borrow Nginx Controller setup files from the Typhoon project because I'm still kind of bewildered by Ingresses.

Deployed my containers

Next, I wrote Kubernetes YAML files for deploying my containers: a private Docker Registry, PostgreSQL and my custom Roller image. Getting the private registry working properly was the biggest challenge. I need private because I don't want to make my custom Roller image public. Next, I'll install Jenkins next for CI/CD of my custom Roller build via the Jenkins Kubernetes plugin.

Let me know if there are any aspects of this that you'd like to see covered in a blog entry, or suggestions for running the cluster without two Ingress Controllers. I've already got a post cooking about installing a TLS secured Docker Registry on Kubernetes.


Powered by Postgresql and Docker Swarm

It was somewhat painful but due to some problems with MySQL and Docker, and some general uneasiness with MySQL, I switched this site from MySQL v5.7 to PostgreSQL v10. I also switched over to Docker Swarm. Here's the Docker-Compose file that I'm using now to run this site:
version: '3.2'

services:

   postgresql:
      image: "postgres:10.0"
      ports:
         - "5432:5432"
      deploy:
         resources:
           limits:
              memory: 50M
      volumes:
         - type: bind
           source: /var/lib/postgresql/data
           target: /var/lib/postgresql/data
      environment:
        - POSTGRES_USER=roller
        - POSTGRES_DB=rollerdb
        - POSTGRES_PASSWORD_FILE=/run/secrets/pg_passwd
      secrets:
        - source: db_passwd
          target: pg_passwd

   roller:
      image: "rwo:latest"
      ports:
        -  "80:8080"
      depends_on:
        - postgresql
      deploy:
         resources:
           limits:
              memory: 800M
      volumes:
        - type: bind
          source: /var/lib/roller
          target: /var/lib/roller
      environment:
        - DB_HOST=postgresql
        - STORAGE_ROOT=/var/lib/roller
        - JAVA_OPTS="-Xmx700m"

secrets:
  db_passwd:
    file: ./db_passwd.txt
It was a pain, but sometimes pain = gain and I learned a lot. I'm hoping the site will be a bit more stable now.

Modernizing the Roller UI

I don't blog very often but I still find time to work on my blog's software: Apache Roller.

Recently, I decided to focus on improving Roller's ancient Struts 2-based user interface (UI). I had considered adding a comprehensive API to Roller and building a new UI based on that API, but wow that is a huge amount of work. Instead, I decided to modernize the Roller UI by using Twitter's Bootstrap components and CSS styles.

So far, I've devoted a couple of weekends to this work and made some pretty good progress. I'm about half-way done. I'm using the Struts2-Bootstrap plugin, adding better client-side form validation with JavaScript and doing my best to improve the overall user experience. You can see an album of the pages I've done so far on Flickr:
Roller UI with Bootstrap
.

I would love any contributions, so if you are interested in helping out, please submit Pull Requests against the bootstrap-ui branch in the Apache Roller repo on GitHub.


Fractal fun with HTML5 and TypeScript

MbCanvas is a fun project that I did in 2015: a simple Mandelbrot Set viewer written in Typescript and using the HTML5 Canvas. I did the project to learn more about Typescript and the HTML5 Canvas and I must say, Typescript very nice -- so much easier to read and write than plain old JavaScript, at least for me.

Here's an example image from the viewer.

mandelbrot set image

The project is fairly easy to build if you've got Node and NPM installed, or you can play around with it here: mbcanvas - Mandelbrot viewer in TypeScript


Usergrid-Vagrant updated for Usergrid 2

GitHub logo

If you're interested in trying the not-yet-released Apache Usergrid 2 you might want to checkout my Usergrid-Vagrant project on GitHub. I just updated the project to support Usergrid 2, using the latest code from the Usergrid "release" brach. The big changes were switching to OpenJDK 8 and adding ElasticSearch. I also rewrote the scripts to use plain old Bash instead of Groovy.

https://github.com/snoopdave/usergrid-vagrant

If you want the old Usergrid 1 Vagrant-file then checkout the "1.x" branch.


Apache Shiro for authentication in Roller

Shiro logo

This is the third of my 2014 side projects that I'm sharing and one that involves the Apache Roller blog server and the Apache Shiro security framework. You might find this interesting if you're considering using Shiro for authentication and authorization, or if your interested in how security works in Apache Roller.

Inspired by my work with Ember.js in Fall 2014, I started thinking about what it would take to build an Ember.js-based editor/admin interface for Apache Roller. To do that, I'd need to add a comprehensive REST API to Roller, and I'd need a way to implement secrity for the new API. I've enjoyed working with Apache Shiro, so I decided that a good first step would be to figure out how to use Apache Shiro in Roller for Roller's existing web interface.

Working over the winter break I was able to replace Roller's existing Spring security implementation with Shiro and remove all Spring dependencies from my Rollarcus fork of Roller. Below I'll describe what I had to do get Shiro working for Form-base Authentication in Roller.

Creating a Shiro Authorizing Realm

The first step in hooking Shiro into Roller is to implement a Shiro interface called ShiroAuthorizingRealm. This interface enables Shiro to do username and password checks for users when they attempt to login, and to get the user's roles.

Below is the first part of the class, which includes the doGetAuthenticationInfo() method, which returns the AuthenticationInfo for a user specified by an AuthenticationToken that includes the user's username. In other words, this method allows Shiro to look-up a user by providing a username and get back the user's (hashed) password, so that Shiro can validate a user's username and password.

ShiroAuthorizingRealm.java (link)
public class ShiroAuthorizingRealm extends AuthorizingRealm {

    public ShiroAuthorizingRealm(){
        setName("ShiroAuthorizingRealm");
        setCredentialsMatcher(
            new HashedCredentialsMatcher(Sha1Hash.ALGORITHM_NAME));
    }

    @Override
    public AuthenticationInfo doGetAuthenticationInfo(
        AuthenticationToken authToken) throws AuthenticationException {

        UsernamePasswordToken token = (UsernamePasswordToken) authToken;

        User user;
        try {
            user = loadUserByUsername( token.getUsername() );

        } catch (WebloggerException ex) {
            throw new AuthenticationException(
                "Error looking up user " + token.getUsername(), ex);
        }

        if (user != null) {
            return new SimpleAuthenticationInfo( 
                user.getUserName(), user.getPassword(), getName());

        } else {
            throw new AuthenticationException(
                "Username not found: " + token.getUsername());
        }
    }

In the code above you can see how we pull the username out of the authToken provided by Shiro and we call a method, loadUserByUserName(), which uses Roller's Java API to load a Roller user object specified by name.

The next method of interest is doGetAuthorizationInfo(), which allows Shiro to look-up a user's Role. This allows Shiro to detmerine if the user is a Roller admin user or a blog editor.

ShiroAuthorizingRealm.java (continued)

    public AuthorizationInfo doGetAuthorizationInfo(
        PrincipalCollection principals) {

        String userName = (String)
            (principals.fromRealm(getName()).iterator().next());

        User user;
        try {
            user = loadUserByUsername( userName );
        } catch (WebloggerException ex) {
            throw new RuntimeException("Error looking up user " + userName, ex);
        }

        Weblogger roller = WebloggerFactory.getWeblogger();
        UserManager umgr = roller.getUserManager();

        if (user != null) {
            List roles;
            try {
                roles = umgr.getRoles(user);
            } catch (WebloggerException ex) {
                throw new RuntimeException(
                    "Error looking up roles for user " + userName, ex);
            }
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            for ( String role : roles ) {
                info.addRole( role );
            }
            log.debug("Returning " + roles.size() 
                + " roles for user " + userName + " roles= " + roles);
            return info;

        } else {
            throw new RuntimeException("Username not found: " + userName);
        }
    }

In the code above you can see that we use the loadUserByUsername() too look-up a user by username, then we use Roller's Java API to get the user's roles. We add those roles to an instance of the Shiro class SimpleAuthorizationInfo and return it to Shir.

Creating a Shiro Authorizing Filter

Now that we've implementated a realm, we've provided Shiro with everything needed to authenticate Roller users and get access to Roller user role information. Next, we need to configure Shiro to enforce roles for the URL apths found in Roller. Shiro includes a RolesAuthorizationFilter, which is close to what we need but not exactly right for Roller. I had to extend Shiro's roles filter so that we can allow a user who has any (not all) of the required roles for a resource.

RollerRolesAuthorizationFilter.java (link)
public class RollerRolesAuthorizationFilter 
    extends RolesAuthorizationFilter {

    @Override
    public boolean isAccessAllowed( 
        ServletRequest request, 
        ServletResponse response, 
        Object mappedValue) throws IOException {

        final Subject subject = getSubject(request, response);
        final String[] roles = (String[]) mappedValue;

        if (roles == null || roles.length == 0) {
            return true;
        }

        // user is authorized if they have ANY of the roles
        for (String role : roles) {
            if (subject.hasRole(role)) {
                return true;
            }
        }
        return false;
    }
}

Configuring Shiro for Roller

Now that we've seen the Java code needed to hook Shiro into Roller, lets look at how we configure Shiro to use that code. We do that using the Shiro configuration file: shiro.ini, as shown below.

shiro.ini (link)
[main]

defaultRealm = org.apache.roller.weblogger.auth.ShiroAuthorizingRealm
securityManager.realms = $defaultRealm

cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
securityManager.cacheManager = $cacheManager

authc = org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authc.loginUrl = /roller-ui/login.rol
authc.successUrl = /roller-ui/menu.rol

rollerroles = org.apache.roller.weblogger.rest.auth.RollerRolesAuthorizationFilter

[urls]

/roller-ui/login.rol          = authc
/roller-ui/login-redirect.rol = authc, rollerroles[admin,editor]
/roller-ui/profile**          = authc, rollerroles[admin,editor]
/roller-ui/createWeblog**     = authc, rollerroles[admin,editor]
/roller-ui/menu**             = authc, rollerroles[admin,editor]
/roller-ui/authoring/**       = authc, rollerroles[admin,editor]
/roller-ui/admin/**           = authc, rollerroles[admin]
/rewrite-status/**            = authc, rollerroles[admin]
/roller-services/rest/**      = authcBasic, rollerroles[admin,editor]

In the configuration file above, you see how we hook in the new ShiroAuthorizingRealm on line 3. The next couple lines are boiler-plate code to hook in Shiro's caching mechanism and then, on line 9, we configure an authentication method called authc, which is configured to use Shiro's Form Authentication feature. And, on line 13, we hook in our new RollerRolesAuthorizationFilter.

Next, we tell Shiro that the login page for Roller is /roller-ui/login.rol and which page to direct a user to on a successful login, /roller-ui/menu.rol, if the user did not specify which page they wanted to access. And finally, on lines 17-25, you see the list of Roller URL patterns that need protection, which authentication method to use (authc or authcBasic) and the authorization filter and roles required for access to the URL pattern.

Wrapping up...

That's all there is to the story of Roller and Shiro so far. I was able to get Roller's form-based authentication working with Shiro, but I did not try to test with OpenID or LDAP, so I assume more work will be necessary to get them working. I did the work in my experimental Rollarcus fork of Roller. You can get the code from the shiro_not_spring branch. Pull requests are quite welcome as are suggestions for improvement. Please let me know if you see anything wrong in the above code.

This work may not find its way into Roller proper, but it plays a part in my the next side-project that I will share: A REST API for Roller with JAX-RS.


Usergrid and Ember.js - part 2

In part one, I explained the basics of the example Usergrid-Ember "Checkin" app, how the index page is displayed and how login is implemented. In part two, I'll explain how Ember.js can be hooked into the Usergrid REST API to store and query JSON objects.

Ember logo

Ember.js includes a feature referred to as Ember-Data, which provides a persistence interface for storing and retrieving JavaScript objects that could be stored in memory, or stored on a server and accessed via REST API.

To use Ember-Data with your REST API you've got to define an Ember-Data model and add an Ember-Data REST adapter. If your REST API differs from what Ember-Data expects then you will probably have to extend the built-in REST adapter to handle your URL pattens, and extend the built-in REST serializer to handle your JSON format. By extending Ember-Data in this way, you can use it to store and query data from Usergrid without using the Usergrid JavaScript SDK at all. Below I'll explain what I had to do to make the Checkin app's Activities collection available via Ember-Data.

Define Ember-Data models

Ember-Data expects each of your REST API collections to have a defined data model, one that extends the DS.Model class. Here's what I added for the Activities collection:

From app.js (link)

App.Activity = DS.Model.extend({
  uuid: DS.attr('string'),
  type: DS.attr('string'),
  content: DS.attr('string'),
  location: DS.attr('string'),
  created: DS.attr('date'),
  modified: DS.attr('date'),
  actor: DS.attr('string'),
  verb: DS.attr('string'),
  published: DS.attr('date'),
  metadata: DS.attr('string')
});

Create a custom RESTAdapter

The Ember-Data REST adapter expects a REST API to follow some common conventions for URL patterns and for JSON data formats. For example, if your REST API provides a collection of cats then Ember-Data will expect your REST API to work like so:

What Ember-Data expects for a cats collection:

  • GET /cats - get collection of cats
  • POST /cats - create new cat.
  • GET /cats/{cat-id} - get cat specified by ID.
  • PUT /cats/{cat-id} - update cat specified by ID.
  • DELETE /cats/{cat-id} - delete cat specified by ID.

Usergrid follows the above conventions for collections, but there are some exceptions. For example, the Usergrid Activities collection. A GET on the /activities path will return the Activities of the users that you (i.e. the currently authenticated user) follow. You don't POST new activities there, instead you post to your own Activities collection at the path /users/{your-user-id}/activities. It works like this:

Usergrid's Activities collection:

  • GET /activities - get Activities of all users that you follow.
  • POST /user/{user-id}/activities - create new Activity for user specified by ID
  • GET /user/{user-id}/activities - get Activities for one specific user.

To adapt the Activities collection to Ember-Data, I decided to create a new model called NewActivity. A NewActivity represents the data needed to create a new Activity, here's the model:

From app.js (Link)

// Must have a special model for new activity because new 
// Activities must be posted to the path /{org}/{app}/users/activities, 
// instead of the path /{org}/{app}/activities as Ember-Data expects.
App.NewActivity = DS.Model.extend({
  content: DS.attr('string'),
  location: DS.attr('string'),
  actor: DS.attr('string'),
  verb: DS.attr('string')
});

Then, in Checkin's custom REST adapter, I added logic to the pathForType() function to ensure that NewActivities are posted to the correct path. Here's the adapter:

From app.js (Link)

App.ApplicationAdapter = DS.RESTAdapter.extend({

  host: Usergrid.getAppUrl(),

  headers: function() { 
    if ( localStorage.getItem("access_token") ) {
      return { "Authorization": "Bearer " 
          + localStorage.getItem("access_token") }; 
    } 
    return {};
  }.property().volatile(), // ensure value not cached

  pathForType: function(type) {
    var ret = Ember.String.camelize(type);
    ret = Ember.String.pluralize(ret);

    if ( ret == "newActivities" ) {
      // Must have a special logic here for new activity 
      // because new Activities must be posted to the 
      // path /{org}/{app}/users/activities, instead of the 
      // path /{org}/{app}/activities as Ember-Data expects.
      ret = "/users/" + Usergrid.user.username + "/activities";
    }
    return ret;
  }

});

You can see a couple of other interesting things in the example above. First, there's the host field which specifies the base-URL of the REST API for the Checkin app. Next, there's the headers() function, which ensures that every request carries the access_token that was acquired during login.

Create a custom RESTSerializer

Ember-Data also has expectations about the JSON format returned by a REST API. Unfortunately, what Ember-Data expects and what Usergrid provides are quite different. The two examples below illustrate the differences:

Ember-Data vs. Usergrid JSON formats

Ember-Data expects collections like this:

{
   cats: [{
       "id": "6b2360d0",
       "name": "enzo",
       "color": "orange"
   },{
       "id": "a01dfaa0",
       "name": "bertha",
       "color": "tabby"
   }]
}






Usergrid returns collections like this:

{
   action: "get",
   path: "/cats",
   count: 2,
   entities: [{
       "uuid": "6b2360d0",
       "type": "cat",
       "name": "enzo",
       "color": "orange"
   },{
       "uuid": "a01dfaa1",
       "type": "cat",
       "name": "bertha",
       "color": "tabby"
   }]
}

Ember-Data expects individual objects like this:

 
{
   cat: {
       "id": "a01dfaa0",
       "name": "bertha",
       "color": "tabby"
   }
}

Usergrid returns individual objects like this:

 
{
   "id": "a01dfaa0",
   "type": "cat",
   "name": "bertha",
   "color": "tabby"
}

You can see two differences above. Ember-Data expects JSON objects to be returned with a "type key" which you can see above: the "cats" field in the collection and the "cat" field in the individual object. Also, Ember-Data expects an object's ID field to be named "id" but Usergrid returns it as "uuid."

The deal with these differences, the Checkin app extends Ember-Data's DS.RESTSerializer. Here's the code:

From app.js (Link)

App.ApplicationSerializer = DS.RESTSerializer.extend({

  // Extract Ember-Data array from Usergrid response
  extractArray: function(store, type, payload) {

    // Difference: Usergrid does not return wrapper object with 
    // type-key. So here we grab the Usergrid Entities and stick 
    // them under a type-key
    var typeKey = payload.path.substring(1);
    payload[ typeKey ] = payload.entities;

    // Difference: Usergrid returns ID in 'uuid' field, Ember-Data 
    // expects 'id'. So here we add an 'id' field for each Entity, 
    // with its 'uuid' value.
    for ( var i in payload.entities ) {
      if ( payload.entities[i] && payload.entities[i].uuid ) {
        payload.entities[i].id = payload.entities[i].uuid;
      }
    }
    return this._super(store, type, payload);
  },

  // Serialize Ember-Data object to Usergrid compatible JSON format
  serializeIntoHash: function( hash, type, record, options ) {

    // Usergrid does not expect a type-key
    record.eachAttribute(function( name, meta ) {
      hash[name] = record.get(name);
    });

    return hash;
  }
});

In the code above you can see how the extractArray() method moves the "entities" collection returned by Usergrid into a type-key field as expected by Ember-Data and how it copies the "uuid" field to add the "id" field that Ember-Data expects.

We also need to transform the data that Ember-Data sends to Usergrid. You can see this above in the serializeInHash() function, which ensures that when data is POSTed or PUT to Usergrid, the type key is removed because that's what Usergrid expects.

Implementing Add-Checkin

To implement Add-Checkin, I added an HTML template called "add-checkin" to Checkin's index.html file. The template displays an Add-Checkin form with two fields: one for content and one for the location. Here's what it looks like in all its modal glory:


screenshot of add-checkin page


Both fields are simple strings (someday I'd like to extend Checkin to use location information from the browser). I won't go into detail here, but it took a bit of research to figure out how to make a Bootstrap modal dialog work with Ember.js. Below you can see the add-checkin controller, which provides a save() function to save a new checkin.

From app.js (Link)

App.AddCheckinModalController = Ember.ObjectController.extend({

  actions: {

    save: function( inputs ) {

      var content = inputs.content;
      var location = inputs.location;
      var target = this.get("target");

      var activity = this.store.createRecord( "NewActivity", {
        content: content,
        location: location,
        verb: "checkin",
        actor: {
          username: Usergrid.user.username
        }
      });

      activity.save().then(
        function( success ) { 
          alert("Saved"); 
        },
        function( error ) { 
          alert("Error " + error.responseJSON.error_description); 
        }
      ); 

    } 
  }
});

In the code above you can see how easy it is to access Usergrid data via Ember-Data now that we've got our custom REST adapter and serializer in place. We create a new Activity with a call to this.store.createRecord() and to save it all we need to do is activity.save().

Time to wrap up...

To sum things up, here are some closing thoughts and observations.

  • If you are considering JavaScript MVC frameworks, then Ember.js is definitely worthy of your consideration. The documentation makes it easy to learn and the community is friendly and helpful.
  • It would be great for Usergrid to provide an Ember.js SDK that makes it really easy to build apps with Ember.js and Usergrid.
  • Ember-Data is an integral part of Ember.js, something that you need to do pretty much anything, but it is treated as a separate package with separate documentation. That is somewhat confusing for a new user.
  • Ember-Data does not include built-in form validation so if your app includes a large number of non-trivial forms, then you may prefer AngularJS over Ember.js.
  • There is a form validation plugin for Ember.js, but it requires the experimental Ember-CLI utility. I tried to use it, but Ember-CLI was unpleasnt enough that I gave up.

I appreciate any feedback you might have about this article, the Usergrid-Ember project and Apache Usergrid. If you want to see how the whole Usergrid-Ember project fits together, find it on GitHub here: Usergrid-Ember. Next up, I'll write about my experiences using Apache Shiro to replace Spring Security in Apache Roller.


Usergrid and Ember.js - part 1

The next one of my 2014 Side projects that I’d like to share is Usergrid-Ember, an experiment and attempt to learn more about Ember.js and Apache Usergrid by implementing the Checkin example from my Usergrid mobile development talk. If you're interested in either Usergrid or JavaScript web development then I hope you'll read on...

Why Ember.js?

Ember logo

Ember.js is one of the leading frameworks for building browser-based apps. It's one of many JavaScript Model View Controller (MVC) frameworks. Generally speaking, these frameworks let you define a set of routes or paths in your app, for example /index, /orders, /about, etc. and map each to some JavaScript code and HTML templates. Handling a route usually means using Ajax to grab some “model” data from a server and using a template to create an HTML “view” of the data that calls functions provided in a "controller" object.

JavaScript MVC frameworks are not simple and each has its own learning curve. Is it really worth the learning time when you can do so much with a little library like jQuery? For most projects I think the answer is yes. These frameworks force you to organize your code in a logical and consistent way, which is really important as projects grow larger, and they provide features that may save you a lot of development time.

Based on what I've seen on the net and local meet-ups, the leading frameworks these days are Ember.js and AngularJS. After I saw Yehudi Katz’s talk at All Things Open, I decided to spend some time learning Ember.js.

Getting started with Ember.js

The first thing you see when you visit the Ember.js site is a big button that says "DOWNLOAD THE STARTER KIT" and so that is where I started. The Starter Kit is a, a minimal Ember.js project with about twenty JavaScript, HTML and CSS files. It's a good way to start: small and simple.

Ember.js Starter Kit files:

screenshot of Starter Kit directory layout

Sidebar: I do hope they keep the Starter Kit around when the new Ember-CLI tool matures. Ember-CLI generates too many magic boiler-plate files and sub-directories for somebody who is trying to understand the basics of the framework. And this is an interesting point of view: Ember-CLI is Making You Stupid by Yoni Yechezkel.

Other stuff: Bower, Grunt and Bootstrap

I like to bite off more than I can chew, so I decided to use a couple of other tools. I used Bower to manage dependencies and Grunt to concatenate and minify those dependencies, and other things like launching a simple web server for development purposes. I also decided to use Bootstrap to provide various UI components needed, like a navbar and nicely styled list views.

I won't cover the details, but it was relatively easy to get Bower and Grunt working. Here are the config files in case you are interested: bower.json and Gruntfile.js. I did hit one problem: when I included Bootstrap as one of my dependencies the Glyphicons would all appear as tiny boxes, so I decided to pull Bootstrap from a CDN instead (looks like there is a fix for that now).

Defining Index Route, Model and Template

Every Ember.js app needs to define some routes. There is a default route for the "/" path which is called the index route, and you can add your own routes using the Router object. The snippet below shows what I needed to get started:

Part of app.js (link)
// create the ember app object
App = Ember.Application.create();

// define routes
App.Router.map(function() {
    this.route("login", { path: "/login" });  
    this.route("logout", { path: "/logout" });
    this.route("register", { path: "/register" });
});

Ember.js will look for the JavaScript Route and Controller objects as well as the HTML template using the names above. For example: Ember.js will expect the login route to be named App.LoginRoute, the controller to be named App.LoginController and the template to be named "login."

Let's talk about the index route. When a user arrives at your app they’ll be directed to the index route. Ember.js will then look for a JavaScript object called App.IndexRoute to provide the model data and JavaScript functions needed for the index page. Here’s a partial view of the index route:

Part of app.js (link)
App.IndexRoute = Ember.Route.extend( {

    // provide model data needed for index template
    model: function() {
        if ( this.loggedIn() ) {
            return this.store.find("activity");
        }
        return [];
    }

});

The index page of the Checkin app shows the Checkin activities of the people that you follow. Above you can see how to route's model() function makes that data available to the template for display. If the user is logged in we call the store.find(“activity”) function to call the Usergrid REST API to get an array of the latest Activity objects. There is some serious Ember-Data magic going on there and I'll cover that in part two of this article.

To display the index route, Ember looks for an HTML template called “index” and will use that template to display the index page. Below is the index template. The template is a Handlebars template and the things that appear in double curly-braces are Handlebars expressions.

Part of index.html (link)

In the above template you can see a couple of {{action}} expressions that call out to JavaScript methods defined in the Checkin app. The part of the code that uses the model is in the {{#each}} loop which loops through each Activity in the model and dispays an HTML list with the the item.content and item.location of each Activity.

Here's what the above template looks like when displayed in a browser:

screenshot of checkin app index page

Implementing Login

In Checkin, login is implemented using HTML Local Storage. Once a user has successfully logged in, the app stores the username and the user's access_token in Local Storage. When user arrives at the index page, we check Local Storage to see if that user is logged in and if not, we direct them to the login route, which in turn displays the login page using the template below.

Part of index.html (link)

The LoginController provides the functions needed by the Login page itself and there are two. There is a login() function (called on line 27 above) that performs the login, and there is a register() function (called on line 31 above) that directs the user to the New User Registration page. Here's a snippet of code from the App.LoginController that provides these two functions:

Part of app.js (link)
App.LoginController = Ember.Controller.extend({

  actions: {

    login: function() { 

      // login by POST to Usergrid app's /token end-point

      var loginData = {
        grant_type: "password",
        username: this.get("username"),
        password: this.get("password")
      };

      $.ajax({
        type: "POST",
        url: Usergrid.getAppUrl() + "/token",
        data: loginData,
        context: this,
        error: function( data ) {

          // login failed, show error message
          alert( data.responseJSON.error_description );
        },
        success: function( data ) { 

          // store access_token in local storage
          Usergrid.user = data.user;
          localStorage.setItem("username", loginData.username );
          localStorage.setItem("access_token", data.access_token );

          // clear the form
          this.set("username", ""); 
          this.set("password", "");

         // call route to handle post-login transition
          this.get("target").send("onLogin"); 
        }
      });
    },

    register: function() {
      this.transitionToRoute("register");
    }

  }
});

The above code shows how to login to a Usergrid app using jQuery's Ajax feature. The login() function takes the username and password values from the login form, puts those in a JSON object with grant_type "password" and posts that object to the /token end-point of the Usergrid app. If that post succeeds, the response will include an access_token. We store that in Local Storage; we'll need to use it in all subsequent calls to Usergrid.

Usergrid fans will notice that I'm not using the Usergrid JavaScript SDK. That's because Ember.js provides Ember-Data, which acts as a very nice REST client and can be adapted to work with the URL structure and JSON formats of just about any REST API. I'll write about that in part two of this article.


2014 side projects

For various reasons, I've always got a couple of coding projects on the back burner, things that I hack around with on weekends and breaks. In 2014, I started four projects and learned about Ember.js, jQuery Mobile, Apache Shiro, Apache CXF and the Arquillian test framework.

I like to share my code, so I've put my code on GitHub and I'm going to write a brief post about each here on my blog. I'll provide links as I go and, of course, I welcome any criticisms and suggestions for improvement that you might have. First up: the Usergrid-Mobile project.

The Usergrid-Mobile project

ApacheCon EU logo
To be honest, Budapest was the goal of this project. In the Spring of 2014, I decided that the best chance of getting to ApacheCon EU in Budapest was to create a great "mobile development with Usergrid" talk, and to do that I needed a great example project. The resulting project shows how to create a dumbed-down Foursquare-style "checkin" app using HTML5, JavaScript, jQuery Mobile and Apache Cordova.

Luckily for me, my talk was accepted for ApacheCon EU and in November I traveled to Budapest (took some photos) and gave the talk there.

I also presented the talk at the All Things Open conference in Raleigh, NC and you can view a video of that talk, Mobile Development with Usergrid on YouTube.



You can find the code for usergrid-mobile on GitHub. I also created a Vagrant File to launch a local instance of Usergrid for demo purposes. It's called usergrid-vagrant.

That's all for now. Next up: Usergrid-Ember.


Phoenix Websites

Phoenix_Websites logo

My eldest son Alex and his friend Austin have started a website design and creation business called Phoenix Websites and, of course, I think this is a great thing. They're not yet out of high school and just getting started, but they've already landed a couple of real live customers. They've got some skills and are not afraid of hard work, so if you're a Triangle-area small business owner and you need a nice new website, check them out.

Like any new business, they need some link love so here we go: Phoenix Websites: Website design and creation services in the Raleigh-Durham Triangle-area. Follow them on twitter at @phoenixrdu


Introduction to Apache Usergrid

I travelled to Budapest, Hungary for a couple of weeks for a very nice vacation with my wife and to speak at ApacheCon EU. Here are the slides that I presented at ApacheCon EU:



(you can also view the presentation on Slideshare.)

And here is the session abstract:

Whether you are building a mobile app or a web app, Apache Usergrid (incubating) can provide you with a complete backend that supports authentication, persistence and social features like activities and followers all via a comprehensive REST API — and backed by Cassandra, giving you linear scalability. All that, and Usergrid is open source too.

This session will explain how you can use Usergrid to provide a back-end for your application. We’ll start with an overview of Usergrid features, then explore in depth how to authenticate users, store data and query data with the REST API provided by a Usergrid server. We’ll develop a simple HTML5 app and package it as a native mobile app via Apache Cordova. We'll also cover how to run Usergrid locally for development and testing.


Talking Usergrid at ApacheCon 2014

ApacheCon 2014

I've been working at Apigee since September 2013 and one of the things I love most about my new job is the fact that I'm actively contributing to open source again.

I'm working on Apache Usergrid (incubating), an open source Backend-As-A-Service (BaaS) that's built on the Apache Cassandra database system. Apigee uses Usergrid as part of Apigee Edge (see the Build Apps part of the docs).

Apigee contributed code for Usergrid to the Apache Software Foundation back in October 2013 and Usergrid is now part of the Apache Incubator. The project is working towards graduating from the Incubator. That means learning the Apache way, following the processes to get a release out and most importantly, building a diverse community of contributors to build and maintain Usergrid.

One on the most important parts of building an open source community is making it easy for people to contribute and and that's why I submitted a talk to the ApacheCon US 2014 conference (April 7-9 in Denver, CO) titled How to Contribute to Usergrid.

The talk is intended to be a briefing for contributors, one that will lead you through building and running Usergrid locally, understanding the code-base and test infrastructure and how to get your code accepted into the Usergrid project.

Here's the outline I have so far:

How to Contribute to Apache Usergrid

  • Motivation
    • Why would anybody want to contribute to Usergrid?
  • First steps
    • The basics
    • Getting signed up
  • Contributing to the Stack
    • Understanding the architecture & code base
    • Building the code. Making and testing changes
    • Running Usergrid locally via launcher & via Tomcat
  • Contributing to the Portal
    • Understanding the architecture & code base
    • Building the code. Making and testing changes
    • Running the portal locally via node.js
  • Contributing to the SDKs
    • Understanding the architecture & code base
    • Building the code. Making and testing changes
  • Contributor workflow: how to get your code into Usergrid
    • For quickie drive-by code contributions
    • For more substantial code contributions
    • For documentation & website changes
  • Contributing Docs and Website changes
    • Website, wiki and GitHub pages
    • How to build the website and docs
  • Roadmap
    • First release
    • New Core Persistence system
    • The two-dot-o branch
    • Other ideas

I'm in the process of writing this talk now so suggestions and other feedback are most welcome.


How Wayin does Cloud Orchestration

I've already mentioned this on Twitter and LinkedIn, but just in case you missed it: I'll be speaking tomorrow night at the Triangle AWS and Triangle DevOps joint meetup at Argyle Social in Durham, NC. I'll give a quick overview of cloud orchestration and Wayin Hub. Then I'll dive into the details of how we automate deployment, scaling and backups for Wayin Hub using AWS and AWS Cloud Formation.

As a little teaser, here's a GIF animation of my automated deployment slide:

Automated Deployment diagram

For more information check the Triangle DevOps page for the event.

UPDATE: slide are now on SlideShare.


Composite Keys in Apache Cassandra

Newer versions of Apache Cassandra include CQL, an SQL-like query language that supports both query, update and delete statements as well as the Data Definition Language (DDL) statements like create and alter for tables and indexes. You can create tables (known as column families in Cassandra lingo) just like you can in a relational database, but there are some caveats.

[Read More]

WIP: Widgets and Gadgets

This is the fifth in my series of Web Integration Patterns. Check out the intro at this URL http://rollerweblogger.org/roller/entry/web_integration_patterns

Synopsis

Allow other web sites and applications to integrate your site into their web pages by providing an embeddable user interface, commonly known as a Gadget or Widget, which allows users to view and interact with your site in the context of other sites.

Motivations

  • By embedding Widgets in your site, you can make your site more useful and informative to your users. Users can access relevant information from other sites in the context of your web site.
  • By allow other sites to embed your Widgets, you can give your site and the services that it offers wider reach. Your users can access and interact with your services in the context of other sites.
[Read More]

Rollarcus: from 9 to 2

rollarcus github logo

I made some progress in Rollarcus over the past couple of weekends, but not a lot. This makes me wonder how I ever found the "nights and weekends" to get Roller started in the first place, but that's a different topic.

What I've done so far in Rollarcus is to simplify things. While I was at Sun, we split Roller up into a number of parts: a weblogger part for blogging, a planet part for RSS/Atom aggregation, a core part for things common to both. After Sun, I worked to move Roller to Maven and further split things up into a total of 9 Maven modules including an assembly for building the release. Now, I think that all these modules are unnecessary -- we never shipped a Roller-Planet application and nobody wants to use parts of Roller -- and even if they did, the modules did not really help.

Here's the before view: apache/roller

Here's the after view: snoopdave/rollarcus

So, in Rollerarcus, I've merged all the modules. Except for one "test utilities" module, all Java code, JSPs and other code is now in one module and much easier to deal with. Next, I'm going to attack the (what I consider to be) unnecessary dependencies and drastically reduce the number of jars in WEB-INF.

UPDATE: The most significant of the changes that I made in Rollarcus have been applied by to Apache Roller and today (August 18, 2013) I removed the Rollarcus repository from Github.

Main | Next page »