Theme and Site Update

Website viewers may notice a couple of site changes.

  1. My tag cloud is now shown at the bottom of the front page.
  2. The main menu links to “Home”, “Technology Category”, “Sports Category”, and “Java Tag”.

I thought that my front page ended a bit abruptly after removing the ability to page through the entire weblog. The tag cloud provides some guidance in exploring my back catalog and is enabled by the latest update to my hexo-theme-landscape work branch.

It’s feels odd, not having a link to my Java Tutorials. Getting my tutorial page on DMOZ was a big step 12 years ago. It was a strong effort back then, but I let it wither on the vine. Now it is time to move on.

CloudFront Checkpoint/Hexo Theme Update

CloudFront is looking good. My added bandwidth cost is about $.20 a month - a very cost effective way to add SSL to my S3 hosted weblog. There is one financial gotcha - the first 1000 URL invalidations are free, but it is $.005 per invalidation after that. I blew through my free invalidations when I added SSL and regenerated every page last month. I think 1000 free invalidations a month would be ample for most people, but not for me.

I have almost 900 total posts. That means I invalidate about 90 URLs with every post (10 posts per page). Or about 10 posts a month, unless I’m willing to pay. I don’t think anyone really wants to page through my entire weblog. And I already updated my archive (2015), category (technology), and tag (java) pages to present a single page of titles last year. So I’ve updated the hexo landscape theme to only generate the first index page.

My fork of hexo-theme-landscape is on github. Take the First Step uses the work branch. I cherry-pick commits from work to master so that I can generate clean pull requests from master.

Cucumber-java and TestNG

With the addition of my jersey client tests, I thought I was ready to add cucumber support to my project. I was wrong. The documentation on using Cucumber and TestNG is a bit sparse and I was getting a bit flustered on where to put the feature definition file.

It turns out that I was making a mountain out of a mole hill. If you put the feature file in the wrong place, then cucumber will tell you where it was looking.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ mvn clean test -q -Dskip=client,browser

-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running TestSuite
Configuring TestNG with: TestNG652Configurator
No features found at [classpath:com/ideoplex/tutorial]

0 Scenarios
0 Steps
0m0.000s

Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.806 sec - in TestSuite

Results :

Tests run: 4, Failures: 0, Errors: 0, Skipped: 0

Read More

Jersey Client with Gson

It doesn’t make sense to have full test coverage of the jersey-gson project in selenium. Let’s fill in the gaps with some jersey-client unit tests.

First, we need a UserMap deserializer to mirror the existing serializer. The existing serializer sends the UserMap as an object whose value is an Array of rows (this simplifies interaction with the DataTables front end). We deserialize the UserMap by iterating through the array, turning each row into a User object, and adding each User object to the Map.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
public class UserMapUnmarshall implements JsonDeserializer<UserMap> {
private static Gson gson = new Gson();

@Override
public UserMap deserialize(JsonElement mapFormat, Type typeOfSrc, JsonDeserializationContext context) {
Iterator<JsonElement> iterate = mapFormat.getAsJsonObject()
.get("data")
.getAsJsonArray()
.iterator();

UserMap users = new UserMap();
while( iterate.hasNext() ) {
JsonObject user = ((JsonElement) iterate.next()).getAsJsonObject();
String email = user.get("email").getAsString();
User add = new User();
add.setEmail( email );
add.setSurname( user.get("surname").getAsString() );
add.setGivenName( user.get("givenName").getAsString() );
users.put( email, add );
}

return users;
}
}

Read More

jersey-gson Content-Type Woes

Another update to my jersey-gson project today. I was trying to add some jersey-client unit tests to the project, but I just couldn’t get the GsonReader and GsonWriter classes to work on the client. The tests worked with manually generated JSON, but failed with automatically generated JSON.

I tried adding a LoggingFilter to examine the actual request being sent to the server, but nothing jumped out at me. Then I added Mono Fiddler as a debugging proxy server and I saw it.

The request succeeded with “Content-Type: application/json”
The request failed with “Content-Type: application/json; charset=UTF-8”

A quick change to GsonWriter and my client requests started working.

1
2
3
4
5
6
7
8
9
10
11
diff --git a/src/main/java/com/ideoplex/tutorial/GsonWriter.java b/src/main/java/com/ideoplex/tutorial/GsonWriter.java
index 9ef181d..95a12c3 100644
--- a/src/main/java/com/ideoplex/tutorial/GsonWriter.java
+++ b/src/main/java/com/ideoplex/tutorial/GsonWriter.java
@@ -42,7 +42,6 @@ public class GsonWriter<T> implements MessageBodyWriter<T> {
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream)
throws IOException, WebApplicationException {
- httpHeaders.get("Content-Type").add("charset=UTF-8");
entityStream.write(gson.toJson(t).getBytes("UTF-8"));
}

Of course, code changes always cascade. Now my selenium browser tests were failing. A little exploration in the browser developer tools revealed that JSON.parse was the culprit. Another code update and the tests were succeeding.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html
index 9568c94..f147ace 100644
--- a/src/main/webapp/index.html
+++ b/src/main/webapp/index.html
@@ -134,13 +134,13 @@
type: "POST",
url: "webapi/myresource/user/post",
data: JSON.stringify(json),
- contentType: "application/json; charset=utf-8",
+ contentType: "application/json",
error: function(xhr,status,error) {
bootbox.alert(xhr.responseText);
},
success: function(data,status,xhr){
form[0].reset();
- $('#users').DataTable().row.add(JSON.parse(data)).draw(false);
+ $('#users').DataTable().row.add(data).draw(false);
}
});
}
@@ -151,14 +151,14 @@
type: "POST",
url: "webapi/myresource/user/edit",
data: JSON.stringify(json),
- contentType: "application/json; charset=utf-8",
+ contentType: "application/json",
error: function(xhr,status,error) {
bootbox.alert(xhr.responseText);
$('#users tbody tr.selected').removeClass('selected');
},
success: function(data,status,xhr){
form[0].reset();
- $('#users').DataTable().row('.selected').data(JSON.parse(data)).draw(false);
+ $('#users').DataTable().row('.selected').data(data).draw(false);
$('#users tbody tr.selected').removeClass('selected');
}
});

25 Oct Autostart Jetty in Maven
01 Nov Jersey Client with Gson

Autostart Jetty in Maven

I’ve made some administrative updates to my jersey-gson project.

First, I’ve updated the pom.xml to automatically start the application in jetty during the maven process-test-classes phase and to automatically stop the jetty instance during the maven install phase. This insures that the webapp will be running and available in the maven test, integration-test and verify phases.

1
diff --git a/pom.xml b/pom.xml
index 318325d..47b6a2c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,6 +47,22 @@
               <groupId>org.eclipse.jetty</groupId>
               <artifactId>jetty-maven-plugin</artifactId>
               <version>${jetty.version}</version>
+              <executions>
+                <execution>
+                  <id>start-jetty</id>
+                  <phase>process-test-classes</phase>
+                  <goals>
+                    <goal>start</goal>
+                  </goals>
+                </execution>
+                <execution>
+                  <id>stop-jetty</id>
+                  <phase>install</phase>
+                  <goals>
+                    <goal>stop</goal>
+                  </goals>
+                </execution>
+              </executions>
             </plugin>
 
             <plugin>

Read More

DataTables Column Search

I spend a lot of time displaying data. And I have developed a bit of a code crush on DataTables since I learned about them. Here’s an example of how the data displayed in two tables can be linked together by a select element and DataTables column search, taken from my example of xml transformed to html in the browser. Here’s how it looks when you narrow the view down to a single group (groups from 3 to 1 and users from 14 to 5)

Narrow to a Single Group

Read More

SSL SNI Alert

My apologies in advance. But if you’re using Internet Explorer on Windows XP, then Take the Next Step is about to go dark. I will be redirecting all traffic from HTTP to HTTPS in the near future. Since I am using Server Name Indication, this site will not be available via Internet Explorer on Windows XP.

Users on a more modern browser/platform combination will be unaffected.