Tweaking the JHipster App – Show me you IDs please, ow wait, don’t!

Like every craft has to have a cool name, a flashy etiquette and needs to be poured into the right glass to please the hipster drinking it, the same applies to serving them a JHipster application: it’s all about presentation!
So let’s dig right into it and shave of some of ’em rough edges of our JHipster app. We’re building on the application we generated in the previous blog post. Code can be found here.

images

Presenting the relationships

Alright. One of the most annoying things that can happen when you’re in the middle of ordering a great craft on a warm Summer day, is some big dude demanding your ID right then and there and you discovering that you left the darn thing at home. So let us get rid of those IDs! Like the ones on the Beer page for example:
Screenshot-2018-4-2 Beers
Those brewery ids don’t mean squat to your average refined beer drinker, so let’s tackle them first. We wanna swap the displayed ids with the corresponding brewery names. But before diving into the code let us take a look at the generated components to see what we’re dealing with.

For every entity JHipster generates a folder into the webapp/app/entities folder. For the Beer entity, for example, we’ve got a beer subfolder. Within we find the beer.component.html that serves as our overview page. The beer-detail.component.html is what is displayed when you press View, the beer-dialog.component.html when you press Create or Edit and the beer-delete-dialog.component.html when you press Delete. They all have their corresponding TypeScript classes.

Screenshot from 2018-04-02 16-14-26

The beer.model.ts handles the model classes, the beer.service.ts and beer-popup.service.ts classes handle the REST calls to the lower Spring Boot layer, beer.route.ts tackles all routes regarding the Beer entity (think of menu items, bookmark urls, foreign key hyperlinks and the Create, View, Edit and Delete links). Everything is packed in a separate Angular module, i.e. beer.module.ts and index.ts just exports all typescript classes in the Beer entity folder upwards in the Angular hierarchy.

Alright. So for changing the overview page displaying our beers with brewery ids, the beer.component.html page is the guy we need. Since the relationship between Beer and Brewery is represented by the entire Brewery class (so not only by the Brewery id) in the Beer class, we have the name for the taking.

Let’s first change the BaseEntity interface (all entities in a relationship are derived from this one) and add an (optional) name to it. The BaseEntity interface is available in the src/main/webapp/shared/model folder.

export interface BaseEntity {
  // using type any to avoid methods complaining of invalid type
  id?: any;
  name?: any;
}

This change is mainly so the IDE won’t complain when we try to use the name property of a relationship somewhere in our html pages.

Now change the beer.component.html so it uses the name of the Brewery instead of the id. First change the table header (for sorting):

<th jhiSortBy="brewery.name">
  <span jhiTranslate="helloBeerApp.beer.brewery">Brewery</span>
  <span class="fa fa-sort"></span>
</th>

Now change the table body (for display):

<td>
  <div *ngIf="beer.brewery">
    <a [routerLink]="['../brewery', beer.brewery?.id ]" >{{beer.brewery?.name}}</a>
  </div>
</td>

Note that we didn’t change the link as it would break the navigation from Brewery to Brewery detail (those bold links are clickable) . That’s it. Refresh the Beer page and revel in the magic! Screenshot-2018-4-2 Beers(3) The view page (beer-detail.component.html) is even simpler, just replace the one line that is displaying the brewery:

<dd>
  <div *ngIf="beer.brewery">
    <a [routerLink]="['/brewery', beer.brewery?.id]">{{beer.brewery?.name}}</a>
  </div>
</dd>

And voilà the detail page is displaying brewery names now instead of useless ids: Screenshot-2018-4-2 Beers(4)

Creating and editing the relationships

The functionality for creating and editing entities are shared on the same html page (beer-dialog.component.html). We want to change the select item linking the beer to the brewery, so that it displays brewery names instead of ids: Screenshot-2018-4-2 Beers(1) This one couldn’t have been easier. Just head over to the div displaying the select item, keep the code that handles displaying/selecting the right relationship based on the brewery id and only change the displayed brewery id into the brewery name:

<div class="form-group">
  <label class="form-control-label" jhiTranslate="helloBeerApp.beer.brewery" for="field_brewery">Brewery</label>
  <select class="form-control" id="field_brewery" name="brewery" [(ngModel)]="beer.brewery" >
    <option [ngValue]="null"></option>
    <option [ngValue]="breweryOption.id === beer.brewery?.id ? beer.brewery : breweryOption" *ngFor="let breweryOption of breweries; trackBy: trackBreweryById">{{breweryOption.name}}</option>
  </select>
</div>

Check out the Edit page now: Screenshot-2018-4-2 Beers(5) See how the brewery name is being displayed instead of the id. How cool is that?!

Autosuggesting

Let’s take this one step further. The inventory item page is still displaying the id for the Beers: Screenshot-2018-4-2 Inventory Items We could change this, like we did in the previous steps and display a list of Beer names. But the list of Beer names could become huge, certainly bigger than the list of breweries. So what if we replaced this guy with an auto-complete item? Sounds great, doesn’t it?! But how do we do that? Enter PrimeNG. PrimeNG is a set of UI components for Angular applications.

Installation

First add the PrimeNG lib to your JHipster application

npm install primeng --save

Next, add the auto-complete component to the module where we’re gonna use it, i.e. inventory-item.module.ts:

...
import { AutoCompleteModule } from 'primeng/autocomplete';
...
@NgModule({
    imports: [
        AutoCompleteModule,
        ...
    ],
    ...
})

Typescript code

For this blog post, we’re just gonna filter the complete Beer list already retrieved by the REST call in the NgOnInit() method – another option would be to omit this initial retrieval and add a REST method that can handle a filter. Then, every time you make a change in the auto-complete item, an instant REST call is made retrieving a list based on the then present filter.

These are the changes needed for the inventory-item-dialog-component.ts:

export class InventoryItemDialogComponent implements OnInit {
...
  beers: Beer[];
  beerOptions: any[];
  ...
  search(event) {
    this.beerOptions = this.beers.filter((beer) => beer.name.startsWith(event.query));
  }
  ...
}

So basically we just add a method filtering the beers starting with the string matching our query. This method will be called every time the input in the auto-complete item changes and will update the selectable options accordingly.

HTML page

Now lets add the auto-complete item on the inventory-item-dialog.component.html page (overwrite the select item):

<p-autoComplete  id="field_beer" name="beer" [(ngModel)]="inventoryItem.beer"  [suggestions]="beerOptions" (completeMethod)="search($event)" field="name" placeholder="Beer"></p-autoComplete>

Check the PrimeNG manuals for more information. The most important piece is adding the field attribute so the auto-complete item can work with a Beer object.

Styling

When you test the JHipster app at this point, you’ll notice the auto-complete functionality actually working already, albeit that the styling looks horrible. Luckily you can get PrimeNG to play nicely along with JHipster’s styling – which is based on the popular Bootstrap CSS library. Just add a few lines to the vendor.css file:

@import '~bootstrap/dist/css/bootstrap.min.css';
@import '~font-awesome/css/font-awesome.css';
@import '~primeng/resources/primeng.css';
@import '~primeng/resources/themes/bootstrap/theme.css';

This is a major improvement. One last optimization is to expand the auto-complete item to a width of 100% just like all the other items on the dialog pages. Add these line to the global.css file:

.ui-autocomplete {
    width: 100%;
}
.ui-autocomplete-input {
    width: 100%;
}

Now, testing the inventory item Edit page you’ll see a nicely integrated auto-complete item: Screenshot-2018-4-11 Inventory Items In the overview and detail pages of the Inventory Item entity we’ll just make the same changes we made for the Beer pages, i.e. exchanging the displayed ids for names: Screenshot-2018-4-11 Inventory Items(1)

Calendar

Alright this beer’s on the house! As a small extra, we’ll add in a calendar item to beautify the item stock level page (and we’ll also change that ugly id). Screenshot-2018-4-16 Item Stock Levels As you can see the Stock Date field could use a good calendar to select the date time, and now we’re on it that ugly xml date presentation we could use without as well.

As we did for the auto-complete item, we’ll be using PrimeNG here again. PrimeNG supports a calendar item. It’s dependent on Angular’s animations module. So let’s first install that guy into our project:

npm install @angular/animations --save

And add the necessary imports to the item-stock-level.module.ts (the module where we’re gonna add the calendar item to).

...
import {CalendarModule} from 'primeng/calendar';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
...
@NgModule({
    imports: [
        CalendarModule,
        BrowserAnimationsModule,
        ...
    ],
    ...
})

Next add the PrimeNG calendar item itself (replace the input item representing the Stock Date) to the item-stock-level-dialog.component.html page:

<p-calendar id="field_stockDate" type="datetime-local" [showIcon]="true" name="stockDate" [(ngModel)]="itemStockLevel.stockDate" showTime="true" hourFormat="24" dateFormat="yy-mm-dd"></p-calendar>

Now, the date format used by JHipster isn’t compatible with this calendar item date format. So let’s change that. Format the stock date returned by the REST service in the item-stock-level-popup.service.ts to a format that the calender item understands, i.e. not the XML date format:

itemStockLevel.stockDate = this.datePipe
  .transform(itemStockLevel.stockDate, 'yyyy-MM-dd HH:mm');

And of course we also need to change the formatting of the stock date when we send it back to the back-end. Alter the item-stock-level.service.ts for this. Just comment out the formatting line (since where sending a plain javascript Date back):

/**
 * Convert a ItemStockLevel to a JSON which can be sent to the server.
 */
private convert(itemStockLevel: ItemStockLevel): ItemStockLevel {
    const copy: ItemStockLevel = Object.assign({}, itemStockLevel);

    // copy.stockDate = this.dateUtils.toDate(itemStockLevel.stockDate);
    return copy;
}

That’s it! Now look at the dialog page when editing an item stock level row. Looks pretty neat (I’ve also changed that id reference into an description reference (not visible in the picture), I’ll not explain it, you can look it up in the code):

Screenshot-2018-4-17 Item Stock Levels

Summary

In this fairly long blog post, we’ve tweaked the front-end of a generated JHipster application. We made quite a few changes to make the application a bit more presentable. We performed the following changes:

  • Changing relationships, replacing ids with meaningful strings;
  • Adding an auto-complete item;
  • Adding a calendar item.

For the last two step we used some PrimeNG components.

In the next blog post we’ll take a closer look at the server side of a JHipster application. So grab yourself a fine craft beer and stay tuned!

References

Advertisements

HelloBeer goes Angular – Finale

Alright guys. This is the last and final episode of our – soon to be released on Netflix – blockbuster series of HelloBeerTM goes Angular starring lots of frustrated beer drinking developers. In this grande finale we’re gonna finish the app we developed in our previous blog posts here and here and add some much needed error handling, css styling and i18n.
The final code can be found here on Github.

Bootstrap CSS

I was using a bootstrap.css file that I snatched somewhere from the internet when I started developing the app, but I recently found out you can just add it as a dependency module. To install the bootstrap version I’ve been using you can add it to the project like this:

npm install bootstrap@3.3.2 --save

Now you can add the import to the styles.css file like this

@import '../node_modules/bootstrap/dist/css/bootstrap.css';

Error handling

The POST method of our REST service expects a beer name to be present in the JSON request. When you leave it blank the beer won’t be added to the inventory, the server will return an error and the JSON error message will be logged to the console. Let’s change that a bit and make it a more in-your-face-experience for the user.

First change the edit-beer.component.ts file to store a possible error in a model variable:

import {Component, EventEmitter, OnInit, Output} from '@angular/core';

import {ApiClientService} from "../services/beer";
import {Beer, Type} from '../services/beer/models';

@Component({
  selector: 'app-edit-beer',
  templateUrl: './edit-beer.component.html',
  styleUrls: ['./edit-beer.component.css']
})
export class EditBeerComponent implements OnInit {

  @Output() onBeerPosted = new EventEmitter<Beer>();

  public beer: Beer = {} as Beer;
  public beerTypes: string[];

  public error: string;

  constructor(private apiClientService: ApiClientService) {
    this.beerTypes = (Object.keys(Type));
  }

  /**
   * Call REST service to POST a beer
   */
  public postBeer(): void {
    this.apiClientService.addToBeerRepositoryUsingPOST(this.beer)
      .subscribe(resp => {
        this.pushBeer(resp.body)
      }, (error => {
        console.log(error);
        this.onError(error.error.message)
      }));
  }

  private pushBeer(beer: Beer): void {
    // add beer to app
    this.onBeerPosted.emit(beer);
    this.reset();
  }

  private onError(message: string): void {
    this.error = message;
  }

  private reset(): void {
    this.beer = {} as Beer;
    this.error = null;
  }

  ngOnInit() {
  }

}

And add the following html snippet at the top of our edit-beer.component.html page (just below the title).

<div [hidden]="!error" class="panel panel-danger panel-body">
  <span class="text-danger">{{error}}</span>
</div>

This will only show the div when there’s actually an error message there.
Now when we try to post a nameless beer to our inventory, we’ll see the error appearing on our screen, like this:
Screenshot-2018-3-5 HbAngularClient
It’s not the most helpful error message, but I’ll leave it up to the reader to pluck a better error message out of the quite verbose REST response.

i18n

Finally, let’s get rid of those ugly beer types. Again this took me a while to get it right, but in the end I found the module that got the job done. It’s called ngx-translate and I basically followed the steps explained on this how-to here.

First add the modules to the app:

npm install @ngx-translate/core --save
npm install @ngx-translate/http-loader --save

Alter the app.module.ts file (consult the how-to page):

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule} from "@angular/forms";
import {HttpClient, HttpClientModule} from '@angular/common/http';
// import ngx-translate and the http loader
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';

import {AppComponent} from './app.component';
import {EditBeerComponent} from './edit-beer/edit-beer.component';

import {ApiClientService} from './services/beer/index';

@NgModule({
  declarations: [
    AppComponent,
    EditBeerComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    })
  ],
  providers: [ApiClientService],
  bootstrap: [AppComponent]
})
export class AppModule {
}

// required for AOT compilation
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http);
}

Next, inject the TranslateService in the app component:

....
import {TranslateService} from "@ngx-translate/core";
....
  constructor(private apiClientService: ApiClientService, private translateService: TranslateService) {
    translateService.setDefaultLang('en');
  }
....

Add the en.json file with the beer type translations to the assets/i18n directory:

{
  "LAGER": "Lager",
  "PILSNER": "Pilsner",
  "PALE_ALE": "Pale Ale",
  "INDIA_PALE_ALE": "India Pale Ale",
  "STOUT": "Stout",
  "OTHER": "Other"
}

Now you can add the translate pipes to the fields displaying the beer types (there’s one on the app.component.html and one on the edit-beer.component.html), like this:

{{beer.type | translate}}

Now test the application. If you’ve made no mistake it should look like this now (check the beer types, they’re nicely translated):
Screenshot-2018-3-5 HbAngularClient(1)

Summary

In these last three blog posts we’ve seen how relatively easy it is to build a small Angular app consuming a Swagger API. The typescript code for consumption was generated by the angular-swagger-client-generator module.

The combination of a Spring Boot back end and an Angular front end is quite popular. As a matter of fact there’s an open source generator out there built around these two frameworks, one that’s gaining quite a lot of traction lately.

In my next blog post I’m gonna market my HelloBeerTM beers to one of the largest groups of craft beer drinkers out there: the hipsters! You guessed it, time to check out JHipster!

References

HelloBeer goes Angular – part II

Alright, let’s keep going. Our Angular clients are getting thirsty! In our previous blog post we’ve built the first part of our Angular app consuming a REST service based on a Swagger API. Let’s finish the app.

Consuming the POST method

To POST beers we’re gonna add a new Form component to our Angular app. We could have put the code in the main app component, but it’s always a good idea to keep your components small. So, to create the new component – we’ll call it edit-beer – just hit:

ng generate component edit-beer

First we’ll fill in the edit-beer.component.ts component code. We need a beer model variable, a list of beerTypes to serve as a drop-down list and a method for posting a beer. Here you go:

import {Component, OnInit} from '@angular/core';

import {ApiClientService} from "../services/beer";
import {Beer, Type} from '../services/beer/models';

@Component({
  selector: 'app-edit-beer',
  templateUrl: './edit-beer.component.html',
  styleUrls: ['./edit-beer.component.css']
})
export class EditBeerComponent implements OnInit {

  public beer: Beer = {} as Beer;
  public beerTypes: string[];

  constructor(private apiClientService: ApiClientService) {
    this.beerTypes = (Object.keys(Type));
  }

  /**
   * Call REST service to POST a new beer
   */
  public postBeer(): void {
    this.apiClientService.addToBeerRepositoryUsingPOST(this.beer)
      .subscribe(resp => {
        this.reset();
      }, (error => {
        console.log(error);
      }));
  }

  private reset(): void {
    this.beer = {} as Beer;
  }

  ngOnInit() {
  }

}

The first time I was testing with the generated code and used the Type interface in my typescript code, I got these messages from IntelliJ:

Screenshot from 2018-02-20 21-09-10

Apparently I was using an older version of typescript, that couldn’t handle string enums. Updating to the newest version of typescript fixed this issue.

Let’s put the form on the html component – edit-beer.component.html – that will enable us to post new beers to our inventory:

<div>
  <div class="well lead">Add a beer</div>
  <form method="POST" class="form-horizontal">
    <div class="row">
      <div class="form-group col-md-12">
        <label class="col-md-3 control-lable" for="input.name">Name</label>
        <div class="col-md-7">
          <input [(ngModel)]="beer.name" type="text" id="input.name" name="name" class="form-control input-sm"/>
        </div>
      </div>
    </div>
    <div class="row">
      <div class="form-group col-md-12">
        <label class="col-md-3 control-lable" for="input.type">Beer type</label>
        <div class="col-md-7">
          <select [(ngModel)]="beer.type" id="input.type" name="type" class="form-control input-sm">
            <option *ngFor="let beerType of beerTypes" [value]="beerType">{{beerType}}</option>
          </select>
        </div>
      </div>
    </div>
    <div class="row">
      <div class="form-group col-md-12">
        <label class="col-md-3 control-lable" for="input.brewery">Brewery</label>
        <div class="col-md-7">
          <input [(ngModel)]="beer.brewery" type="text" id="input.brewery" name="brewery" class="form-control input-sm"/>
        </div>
      </div>
    </div>
    <div>
      <input (click)="postBeer()" title="OK" class="btn btn-primary custom-width float-right"/>
    </div>
  </form>
</div>

Note the postBeer() method coupled to the button click event binding.

Add the edit-beer component at the bottom of the app component and fire up the app to see my next rookie mistake appearing in the console:

Can't bind to 'ngModel' since it isn't a known property of 'input'.

This took me while to figure out. The error – though a bit vague – is all about forgetting to import the FormsModule in the app module, so let’s fix that:

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule} from "@angular/forms";
import {HttpClientModule} from '@angular/common/http';

import {AppComponent} from './app.component';
import {EditBeerComponent} from './edit-beer/edit-beer.component';

import {ApiClientService} from './services/beer/index';

@NgModule({
  declarations: [
    AppComponent,
    EditBeerComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [ApiClientService],
  bootstrap: [AppComponent]
})
export class AppModule {
}

Now after running the app again, we’ll see a familiar screen appearing:
Screenshot-2018-3-4 HbAngularClient

You can enter a new beer and after hitting the OK button, the beer is posted. When you refresh the screen (don’t worry we’re gonna fix that), you can see that the list is updated with the beers you just added.

Updating the beer inventory instantly

Hitting refresh to update the beer inventory after adding a new beer every time, is bound to piss some clients off, especially when one of ’em is an angry drunk. So let’s fix that asap!

Now how do we do that? We obviously need a way to communicate between the edit-beer component and the app component: events to the rescue!

The application will require a few changes. Let start with the edit-component that will fire the event. This is the new code:

import {Component, EventEmitter, OnInit, Output} from '@angular/core';

import {ApiClientService} from "../services/beer";
import {Beer, Type} from '../services/beer/models';

@Component({
  selector: 'app-edit-beer',
  templateUrl: './edit-beer.component.html',
  styleUrls: ['./edit-beer.component.css']
})
export class EditBeerComponent implements OnInit {

  @Output() onBeerPosted = new EventEmitter<Beer>();

  public beer: Beer = {} as Beer;
  public beerTypes: string[];

  constructor(private apiClientService: ApiClientService) {
    this.beerTypes = (Object.keys(Type));
  }

  /**
   * Call REST service to POST a new beer
   */
  public postBeer(): void {
    this.apiClientService.addToBeerRepositoryUsingPOST(this.beer)
      .subscribe(resp => {
        this.pushBeer(resp.body)
      }, (error => {
        console.log(error);
      }));
  }

  private pushBeer(beer: Beer): void {
    // add beer to app
    this.onBeerPosted.emit(beer);
    this.reset();
  }

  private reset(): void {
    this.beer = {} as Beer;
  }

  ngOnInit() {
  }

}

The REST service will return a beer after it’s been posted. So we’ll gonna send that new beer on the event to the app component. That guy will use it to update its beers list.

The event will be emitted from the edit-beer.component, so reflect that in the app.component.html, here you’ll glue the methods from the app and edit-beer components together:

<app-edit-beer (onBeerPosted)="onBeerPosted($event)"></app-edit-beer>

Last piece of the puzzle is catching the event in the app component. Just add this code snippet to the app.component.ts and you’re done.

public onNewBeer(beer: Beer): void {
  this.beers.push(beer);
}

Test the app again and see the magic happening when you add a new beer. Flashy is it not?

Summary

We’re almost there. I was planning to finish this blog in 2 parts, but like with every great blockbuster movie of the 80s, we need a third installment.

In the last part of our HelloBeer goes Angular trilogy we’ll wrap it all up with some user-friendly error handling. We’ll also add i18n to our app to improve upon those ugly beer types. And then we’re really done!

Devoxx 2010 impressions – day 2

My second and (unfortunately) last day at Devoxx i visited two completely different talks.

The first talk was about Cassandra, one of the many nosql databases that have emerged in the last years. Nosql was definitely one of the biggest topics on Devoxx. Four university slots were reserved for it. Apart from the Cassandra talk, there was a talk on Hadoop, MongoDB and HBase.

The second talk discussed two of the most used JavaScript libraries today, Prototype and jQuery.

Cassandra by Example

by Jonathan Ellis

Cassandra is one of the many nosql databases around. It offers scalability, reliability and high availability. It has good clustering and failover capabilities. It also integrates some Hadoop functionality for analyzing its datastore. Currently it has support for Pig and Hive. The scalability and reliability comes at price though. Cassandra doesn’t support ACID transactions and has only limited support for ad-hoc queries (hence the name nosql). This makes it especially suitable for very large internet applications where ACID isn’t that big a deal. Applications like Twitter and Facebook come to mind.

The idea behind Cassandra (and other nosql databases) is that IO should be optimized. Data closely related to each other is stored (often redundantly) close together on disk, thus significantly reducing IO overhead. Compared to relational databases, where scaling is accomplished predominantly by increasing cpus and memory, Cassandra scales by optimizing IO which comes at the cost of increased disk space. But since disk space had become relatively cheap these days, as compared to memory and processor units, this is a fair price to pay.

There is a another price to pay however. As mentioned, Cassandra stores a lot of data redundantly. Data related to a particular query eg. is stored in one row. This highly increases complexity. Since Cassandra doesn’t support referential integrity, so there’s no such thing as a cascaded delete for example, it’s up to the application (hence the programmer) to make sure that the stored data remains consistent with the datamodel. And as mentioned before there is limited support for ad-hoc querying

A good deal of the talk showed some examples on Cassandra’s shell client and Cassandra’s java api Hector. The examples were pretty complex, and coding against the API comes with a lot of boilerplating. Jonathan made and interesting comparison. He compared Hector with JDBC (for relational databases) and foresaw a JPA-like API in the near future. Now this would be really interesting from a JEE programmer point of view. JPA could abstract away the fact that you’re programming against a nosql database! All the examples Jonathan showed,  belonged to an online example Twitter-like application called Twissandra. The example project regarding Hector is called Twissjava.

At the end Jonathan mentioned some more advanced features of Cassandra

  • Batch insertions;
  • Secundary indexes, i.e. the ability to add indexes on additional columns in a row;
  • SuperColumns, which are basically maps of columns, used to denormalize data to avoid extra queries;
  • RipCord, a management suite for Cassandra;
  • JMX monitoring.

All in all, a very interesting talk. I’m definitely going to dive in in this topic in the near future.

And here’s a link to the slides.

Ajax Library Smack down: Prototype vs. jQuery

by Nathaniel Schutta

In the first half of his very inspiring talk Nathaniel Schutta compared two of the most used JavaScript libraries, i.e. Prototype and jQuery. Both have their pros and cons and which one is best suited for the job is mostly a matter of taste.

Both libraries offer a lot of the same goodies:

  • cross browser abstractions;
  • simplified AJAX;
  • CSS selectors;
  • event handling;
  • widgets, effects, animations;
  • javascript utilities.

Both have excellent online documentation available, are widely used, have good community support and are very small libraries.

Apart from the similarities, there are also a lot of differences between the two. According to Nathaniel Prototype has been developed from a programmer’s viewpoint (API centric), whereas jQuery is more focussed on HTML elements. Here’s a list of the pro’s and con’s.

Prototype pros:

  • adds useful functions to core elements (on very very large pages this can cause a significant memory footprint);
  • widgets and effects available via script.aculo.us;
  • ruby flavored javascript;
  • widely used.

Prototype cons:

  • no minified version;
  • performance not always a priority;
  • pollutes the global namespace.

jQuery pros:

  • focussed on HTML elements;
  • doesn’t pollute global namespace;
  • dom traversal is a snap;
  • extensive array of plugins available.

jQuery cons:

  • parameter ordering in apis not alway intuitive;
  • plugins required for a variety of functionality;
  • some functions reassign this.

I’m definitely not an expert on using either one of these libraries but after Nathaniel compared both libraries i think jQuery has a slight advantage. This is because it had plugins in mind when it was first designed. There are a lot of plugin libraries available and you can pick the ones you need and omit the ones you don’t need. In Prototype you only have two options: with or without script.acul.us.

In the second half of his talk he showed some nice examples on using jQuery. One of the points he made is that contrary to public opinion JavaScript isn’t that hard a language. And indeed all his examples where pretty simple. He also stressed the point that code should be self explanatory, so the name of a method for example is very important and should clearly and without any reason for debate state what the method actually does. And of course on more than one occasion he made a case that the question of using one of the open-source JavaScript libraries or not is a no-brainer.
All probably very open doors to most programmers, but still i honestly believe that in practice a lot of these rules are violated.

Here’s a link to the slides.

Seam-gen and groovy

I recently added a groovy action class to my seam-gen project. After a while eclipse’s auto-build kept giving me these misleading ant errors in the groovy.compilemodel task:

groovyc doesn't support the "srcdir" attribute

It took me a while to fix this issue. When i ran the compile target manually there was no problem, so eventually i figured it had to do with the explode launcher that was generated by seam-gen. You need to let it run in a separate JVM.
First, right-click on the project and select “Properties”.

Properties for open18

Next, select “Builders” and Edit the explode builder.


Edit Configuration
Edit configuration

Finally, click the “JRE” tab en select “Separate JRE” as the runtime JRE.

After this the auto-build error should be gone.