Cleaning Code Practically Episode 1

8 10 2009

Last Øredev I were at a presentation done by Robert Martin, author of the book Clean Code. I were really impressed by what his message where. So we are trying to follow his word at work and today a topic came up. So a colleague had this code:


public String getRequestString() throws MQException {
String request = "";
request += Helper.leftRightFilled(true, String.valueOf(getSessionNumberAndIncreaseIt()), '0', 3);
request += Helper.leftRightFilled(true, getVersion(), '0', 3);
request += Helper.leftRightFilled(true, getTransaction(), 'X', 4);
request += Helper.leftRightFilled(true, getLanguage(), 'X', 2);
request += Helper.leftRightFilled(true, getCallersPhoneNumber(), '0',16);
request += Helper.leftRightFilled(false, dynamicSettingMQ.getCustomerNumber(), ' ', 16);
request += Helper.leftRightFilled(true, String.valueOf(dynamicSettingMQ.getNumberOfUnsucceededCalls()), '0', 3);
return request;
}

I intermediately though that could be more readable, so I just pushed a lot into functions, and did a little to the helper class:

public String getRequestString() throws MQException {
String request = "";
request += createSessionNumberString();
request += createVersionString();
request += createTransactionString();
request += createLanguageString();
request += createCallersPhoneNumberString();
request += createCustomerNumberString();
request += createNumberOfUnsucceededCallsString();
return request;
}
protected String createCallersPhoneNumberString() throws MQException {
return Helper.leftRightFilled(true, getCallersPhoneNumber(), '0', 16);
}
protected String createCustomerNumberString() throws MQException {
return Helper.leftRightFilled(false, dynamicSettingMQ.getCustomerNumber(), ' ', 16);
}
protected String createLanguageString() throws MQException {
return Helper.leftRightFilled(true, getLanguage(), 'X', 2);
}
protected String createNumberOfUnsucceededCallsString() throws MQException {
return Helper.leftRightFilled(true, dynamicSettingMQ.getNumberOfUnsucceededCalls(), '0', 3);
}
protected String createSessionNumberString() throws MQException {
return Helper.leftRightFilled(true, getSessionNumberAndIncreaseIt(),'0', 3);
}
protected String createTransactionString() throws MQException {
return Helper.leftRightFilled(true, getTransaction(), 'X', 4);
}
protected String createVersionString() throws MQException {
return Helper.leftRightFilled(true, getVersion(), '0', 3);
}
}

At first the colleague thought it was nice, but then remembered he really needed a overview of locations used in the string manipulation. So a thing between the two are needed:

public String getRequestString() throws MQException {
String request = "";
request += createSessionNumberString('0', 3);
request += createVersionString('0', 3);
request += createTransactionString('X', 4);
request += createLanguageString('X', 2);
request += createCallersPhoneNumberString('0', 16);
request += createCustomerNumberString(' ', 16);
request += createNumberOfUnsucceededCallsString('0', 3);
return request;
}
protected String createCallersPhoneNumberString(char fillWith, int length) throws MQException {
return Helper.leftRightFilled(true, getCallersPhoneNumber(), fillWith,length);
}
protected String createCustomerNumberString(char fillWith, int length) throws MQException {
return Helper.leftRightFilled(false, dynamicSettingMQ.getCustomerNumber(), fillWith,length);
}
protected String createLanguageString(char fillWith, int length) throws MQException {
return Helper.leftRightFilled(true, getLanguage(), fillWith,length);
}
protected String createNumberOfUnsucceededCallsString(char fillWith, int length) throws MQException {
return Helper.leftRightFilled(true, dynamicSettingMQ.getNumberOfUnsucceededCalls(), fillWith,length);
}
protected String createSessionNumberString(char fillWith, int length) throws MQException {
return Helper.leftRightFilled(true, getSessionNumberAndIncreaseIt(),fillWith,length);
}
protected String createTransactionString(char fillWith, int length) throws MQException {
return Helper.leftRightFilled(true, getTransaction(), fillWith,length);
}
protected String createVersionString(char fillWith, int length) throws MQException {
return Helper.leftRightFilled(true, getVersion(), fillWith, length);
}

Im not satisfied, but not sure it can be done more clean? And if you are wondering about why we are doing all this string manipulation, we are working with some legacy MQ. If we split up the code without parameters as above we lose the quick overview.. But could the code be simplified even more please come with your suggestion..





Eclipse 3.2 And Subversive

3 07 2009

Seems like gremlins in my machine, first time we at work did a branch the branch received changes from trunk. But did not push stuff back to trunk. Merging was simple since the branch always was up to date with trunk and only had a few changes..

Some time passed and we tried doing a new branch, a few problems, but at last we finally made the branch. Worked with it, but now subversive and tortoise refuses to merge the branch back again! I’ve tried a million things. In the end I checked out trunk removed the affected parts and added the ones from the branch and commitet those again. Just to get our system into working order..

My primary suspicion now are that doing branches are very affected by which svn provider you chose, nothings confirmed, but I know we’ve switched providers since the first successful branching.

Any other experiencing troubles with this ancient version of eclipse & subversive?





Integration Testing With Nortel SCE / Part 1

3 04 2009

So you are developing with the Nortel SCE and want todo integration testing. Theres no support for it in the framework itself. So we think and think. The SCE communicates via voicexml or VXML towards the MPS. This happens over http protocol, that means the we can use Jmeter to sniff the communication between MPS and SCE (JBOSS / struts). So in practice to make this work you need to setup the http proxy on jmeter and then go into the SBClient.cfg located here : C:\Program Files\Nortel Networks\SelfService\PERIvxml\config\ on a standard installation , edit these two lines:


client.inet.proxyServer VXIString localhost
client.inet.proxyPort VXIInteger 9000

Proxy server are the machine where you have jmeter running and port are the one you specified when setting up the proxy, id recommend using 9000 since the default 8080 clashes with the SCE Jboss port. After changing the parameters you need to restart the MPS service.

So there are two was of recording, on your local machine using the mock interface provided with SCE / eclipse ( execution view / WVADS ). Or on your test facility where you actually can dial in as normal, and record the scenarios. Just remember when you end Jmeter the proxy goes down aswell, meaning the MPS & SCE can no longer communicate, just comment out the 2 lines in sbclient.cfg to get it working again.

Tips

  1. Remember to switch recording controller in jmeter between scenarios. And one more thing this will only record the dialog between SCE and MPS, not the audio server.
  2. If you add appropriate listeners to your jmeter scenario when you replay you can even see the vxml responses.

Heres how a scenario from a very simple application looks (Just playing a couple of prompts):

SCE Jmeter Scenario

SCE Jmeter Scenario

After recording the scenarios they can now be replayed at wish for example as part of integration test. In the next part I’ll try to digest howto put in test coverage with coberatura, so we get some metrics on how much of our code actually are tested with this approach. Now sadly since SCE does a lot of auto generation I think the process will be partially manual, so we cannot employ a building server like Hudson for this:( If you have any ideas on howto run the SCE auto generation as a MOJO from maven or something please do not hesitate to write. As always comments are more than welcome :)

If you are new to jmeter you can read more here, Jmeter site





Apache Wicket Merchandise

19 02 2009

In late 2008 I got the permission (by signing a contract) from ASF to create and run a Webshop that sells Wicket Merchandise, the shop donates 5% of profit to ASF the rest goes to the Wicket community. If you want to buy some merchandise go here http://www.cafepress.com/apachewicket .

The Apache Wicket Merchandise Shop has awarded these people:

  • 2009 – Jeremy Thomerson , for his work organizing wicketstuff core, he got golf t-shirt ( http://www.cafepress.com/apachewicket.317295373 )
  • 2009 – Daan van Etten , for creating the grapichs for the merchandise, he got the mug ( http://www.cafepress.com/apachewicket.317295372 )

The idea are to continue to use profits to award people that has done something special for the wicket community, like Wicket committers or WicketStuff committers etc.

If you have someone that you would like to nominate to receive some merchandise please write it as a comment here, please write a few lines why and if you have contact information you can mail it too me. I’ll add them to the vote list.

regards Nino





Wicket continues to impress me

11 12 2008

So I wanted to put in a conditional css thing to fix a IE problem, todo this thing in wicket I just though up a way. And wrote the code, it just worked:)

Heres how:
Markup (in head):

*style wicket:id="ieStyle" type="text/css"*

*/style*


A simple webmarkupcontainer, to put in the hack (with a resource reference)::

add(new WebMarkupContainer("ieStyle"){

@Override
protected void onComponentTagBody(MarkupStream markupStream,
ComponentTag openTag) {
super.onComponentTagBody(markupStream, openTag);
String csshoverurl=urlFor(new ResourceReference(BasePage.class,"csshover2.htc")).toString();
getResponse().write("" +
"body {" +
"behavior: url("+csshoverurl+");" +
"}");

}

}

And to finish it up make it conditional so only IE picks it up, by adding a behavior:

public class IECheckBehaviorBehavior extends AbstractBehavior {
public IECheckBehaviorBehavior() {
}
@Override
public void beforeRender(Component component) {
super.beforeRender(component);
Response response = component.getResponse();
response.write("*!--[if lt IE 7]>--*");
}
@Override
public void onRendered(Component component) {
super.onRendered(component);
Response response = component.getResponse();
response.write("*![endif]--*");
}
}

The result:

*!--[if lt IE 7]>--*
body {behavior: url(resources/zeuzgroup.web.page.BasePage/csshover2.htc;jsessionid=1pjzdpc4j8asn);}
*![endif]--*

Simple and and almost clean :)

Ps I had to substitute the less than equal and greater than equal sign with *





OpenID, the challenge Attributes

11 12 2008

So what’s the fuss about openID? Well the idea are to have one id provider for all the sites that require authentication.

And if you go a bit further and you do at sometime, you’ll want to get some details about the user, like email or full name. So the guys at openID implemented something called attribute exchange. And if you are in the java world like I am you want something simple, so I turned to openID4Java. The idea are that you let the user put in the id on your web page just something like johndoe.openid.org and then you forward the user to openid.org and lets openid.org validate your user and then openid.org will forward the user back to you using an url you specified. And if you really need some properties, you can add a sreg (OpenID Simple Registration Extension) for each property to make the user enter it at the provider ( however not all providers supports these things ).

Well onto the code :

Code for requesting the provider

// --- placing the authentication request ---
public String authRequest(String userSuppliedString,
HttpServletRequest httpReq, HttpServletResponse httpResp,
String returnToUrl) throws IOException, ServletException {
try {
// configure the return_to URL where your application will receive
// the authentication responses from the OpenID provider

// perform discovery on the user-supplied identifier
List discoveries = manager.discover(userSuppliedString);

// attempt to associate with the OpenID provider
// and retrieve one service endpoint for authentication
DiscoveryInformation discovered = manager.associate(discoveries);

// store the discovery information in the user's session
httpReq.getSession().setAttribute("openid-disc", discovered);

// obtain a AuthRequest message to be sent to the OpenID provider
AuthRequest authReq = manager.authenticate(discovered, returnToUrl);
FetchRequest fetch = FetchRequest.createFetchRequest();

//
// SRegRequest sregReq = SRegRequest.createFetchRequest();
//
// sregReq.addAttribute("fullname", true);
// sregReq.addAttribute("nickname", true);
// sregReq.addAttribute("email", true);
fetch.addAttribute("Fullname", "http://axschema.org/namePerson/",
true);
fetch.addAttribute("Email", "http://axschema.org/contact/email",
true);

// tell the email coint
fetch.setCount("Email", 1);
AuthRequest req = manager.authenticate(discovered, returnToUrl);
req.addExtension(fetch);
// authReq.addExtension(sregReq);
if (!discovered.isVersion2()) {
// Option 1: GET HTTP-redirect to the OpenID Provider endpoint
// The only method supported in OpenID 1.x
// redirect-URL usually limited ~2048 bytes
httpResp.sendRedirect(authReq.getDestinationUrl(true));
return null;

} else {
httpResp.sendRedirect(authReq.getDestinationUrl(true));
return null;
// // Option 2: HTML FORM Redirection (Allows payloads >2048
// bytes)
// RequestDispatcher dispatcher =
// httpReq.getRequestDispatcher(OpenIdSignInPage.MOUNTPATH);
// httpReq.setAttribute("parameterMap",
// authReq.getParameterMap());
// httpReq.setAttribute("destinationUrl",
// authReq.getDestinationUrl(false));
// dispatcher.forward(httpReq, httpResp);
}
} catch (OpenIDException e) {
// present error to the user
}

return null;
}

The code that recieves the response from the provider:

// --- processing the authentication response ---
public User verifyResponse(HttpServletRequest httpReq) {
try {
// extract the parameters from the authentication response
// (which comes in as a HTTP request from the OpenID provider)
ParameterList response = new ParameterList(httpReq
.getParameterMap());

// retrieve the previously stored discovery information
DiscoveryInformation discovered = (DiscoveryInformation) httpReq
.getSession().getAttribute("openid-disc");

// extract the receiving URL from the HTTP request
StringBuffer receivingURL = httpReq.getRequestURL();
String queryString = httpReq.getQueryString();
if (queryString != null && queryString.length() > 0)
receivingURL.append("?").append(httpReq.getQueryString());

// verify the response; ConsumerManager needs to be the same
// (static) instance used to place the authentication request
VerificationResult verification = manager.verify(receivingURL
.toString(), response, discovered);

// examine the verification result and extract the verified
// identifier
Identifier verified = verification.getVerifiedId();
if (verified != null) {
AuthSuccess authSuccess = (AuthSuccess) verification
.getAuthResponse();
if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
FetchResponse fetchResp = (FetchResponse) authSuccess
.getExtension(AxMessage.OPENID_NS_AX);
return filluser(fetchResp);
}

if (authSuccess.hasExtension(OPENID_NS_SREG1_1)) {
log.info("got info:"
+ authSuccess
.getParameterValue("openid.sreg.email"));
log.info("got info:"
+ authSuccess
.getParameterValue("openid.sreg.fullname"));

User user = new User();
user.setEmail(authSuccess
.getParameterValue("openid.sreg.email"));
user.setName(authSuccess
.getParameterValue("openid.sreg.fullname"));
return user;

}

// return verified; // success
}
} catch (OpenIDException e) {
// present error to the user
}

return null;
}

private User filluser(FetchResponse fetchResp) {

List emails = fetchResp.getAttributeValues("email");
String email = emails.get(0);
List names = fetchResp.getAttributeValues("name");
String name = names.get(0);

User user = new User();
user.setEmail(email);
user.setName(name);
return user;

}

So the idea are good and the authentication works, but my problem are that I cannot get the providers to provide the ax properties. So I’ll be following up on howto do this in this post. I hope I succeed at some point, because for me openid without ax are almost worthless. At this point I dont know if it’s the openID4java implementation or the openID providers. If you have any pointers on howto do this please comment





new stuff in Wicketstuff OpenLayers integration

9 12 2008

So I’ve added a few things and done a cleanup on the Wicketstuff OpenLayers integration.

  • We are now using JTS (http://www.vividsolutions.com/Jts/JTSHome.htm) directly.
  • You are now able to draw geometry’s using the new DrawListenerBehavior
    • Geom’s are pushed to java using JTS
  • Remove the drawControl using the RemoveDrawControl behavior.

Heres some screens :

Drawing

Drawing

FeedBack from serverside (just outputting the WKT of the geom)

interaction 01

Using a little JTS:

A little JTS power

And if you’re wondering why is this cool? Well because above interactions are passed to server side, using the Wicketstuff Openlayers integration requires no knowledge of javascript, its wrapped nicely for you.

Heres the link to a little more about the library:

http://wicketstuff.org/confluence/display/STUFFWIKI/wicket-contrib-openlayers

And if you combine this with hibernate spatial, you can since hibernate spatial supports JTS.. You have a really cool simple GIS system :)





testalicious testing

3 11 2008

Test Mashup, TDD / BDD

So these days test driven or behavior driven development are hot around my coordinates. Im going to write a bit about pratical usage of BDD using selenium & jBehave. With backup tools such as maven, cobertura and selenium.

We all hate to maintain large code bases of tests, tests are nice ( and necessary ) but sometimes you just get cluttered by them.

Introducing jBehave

So what if you could have a minimal amount of code and write something like this:

When user goes to homepage
homepage are rendered

Taking it a bit further:


Given a user nino with password dummy
When user goes to homepage and does a login
Then user are logged in and shown profilepage

That would be nice right? In jBehave you archive this by a blend of things, i’ll only cover a subset.

Steps
In your steps class you something like the below code, notice that I put in selenium. So the steps are sort of a mini test framework which the scenarios can utilize.


@When("a user visits $page")
public void visits(String page) {
selenium.open("http://localhost:8080/" + page);
}
@Then("$page are rendered")
public void seesPage(String page) {
Ensure.ensureThat(selenium.getLocation().compareToIgnoreCase(
"http://localhost:8080/" + page) == 0);
Ensure.ensureThat(!selenium.isTextPresent("HTTP ERROR: 404"));
}

Scenario
The scenario are a plain text test, which utilizes the steps above. Something like this:

When a user visits homepage
Then home are rendered
When a user visits errorpage
Then errorpage are rendered

As you can see you could actually put in use cases, and things suddenly got a lot easier to discuss with customers, your tests are readable by non technical eyes and of course it’s not limited to web development. And your maintenance code base got smaller since what you need to write in java have shrunken, you are only building a small framework for the scenarios to utilize. Really really cool!

As you can see jBehave fit’s both for unit testing and the more obvious integration testing.

Introducing Cobertura

While you test it’s still nice to know your code coverage, cobertura’s nice for this as it gives you simple readable reports and it’s transparent to use. Just include a small mojo in your parent pom:

In your parent pom

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemProperties>
<property>
<name>
net.sourceforge.cobertura.datafile
</name>
<value>
target/cobertura/cobertura.ser
</value>
</property>
</systemProperties>
</configuration>
</plugin>

And in the project pom using it

<plugins>

<reporting>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<configuration>
<formats>
<format>html</format>
</formats>
</configuration>
</plugin>

</plugins>
</reporting>
</project>

You will then get reports looking like this:

Cobertura report

Cobertura report

And you can even see which lines are touched in your code:

See what lines are touched by tests

See what lines are touched by tests

Introducing Selenium

Automatic independent browser tests, if your doing web development this is almost a must have, unless you like to do manual tests a lot. However if you are using code coverage which are using byte code instrumentation, you could loose track of what’s tested and what not. A way around this are perhaps to start a embedded jetty server as part of your test, then in theory you should be back on track. Since byte code instrumentation should be able to track again…





JPQL example queries

28 10 2008

Looking for JPQL queries, look no further. I use this as a reference page myself.

Search for Persons which all live in San Fransisco, New York or Frederikssund, traversal over single relation

SELECT p FROM Person WHERE p.city.id IN ("SF","NY", "FS")

Search for Persons with some of these tags(tags is a list of tags), traversal over list relations: Married, Divorced, OverTheHill

SELECT p FROM Person P JOIN p.tags t WHERE t.name IN ("married","divorced", "overthehill")

Above could be slow..
Search with enumerations:

SELECT p FROM Person WHERE p.enum = com.mypackage.enum.value
</code

Copy paste stuff:

public List searchForEvents(City city,
List eventTypeList,
List eventAdmittance,
List categoryTypeList)
{
List events = new ArrayList();
List categories = new ArrayList();
List admittanceTypes = new ArrayList();
if (eventTypeList.size() > 0 || categoryTypeList.size() > 0
|| eventAdmittance.size() > 0) {
for (EventType event : eventTypeList) {
events.add(EventType.class.getCanonicalName() + "."
+ event.name());
}

for (CategoryType categoryType : categoryTypeList) {
categories.add(CategoryType.class.getCanonicalName() + "."
+ categoryType.name());

}
for (EventAdmittanceType admittanceType : eventAdmittance) {
admittanceTypes.add(EventAdmittanceType.class
.getCanonicalName()
+ "." + admittanceType.name());

}

}
String jpql = "select e from Event e WHERE e.city.id='" + city.getId()
+ "'";
// types
List typesList = new ArrayList();

if (events.size() > 0) {
typesList.add("e.eventType IN ( " + buildJPQL(events, ",") + " ) ");
}
if (categories.size() > 0) {
typesList.add(" e.categoryType IN ( " + buildJPQL(categories, ",")
+ " )");
}
if (admittanceTypes.size() > 0) {
typesList.add(" e.eventAdmittanceType IN ( "
+ buildJPQL(admittanceTypes, ",") + " )");
}
if (typesList.size() > 0) {
jpql += " and " + buildJPQL(typesList, "and");
}

return getJpaTemplate().find(jpql);
}

private String buildJPQL(List sqlList, String delimiter) {
String constructedSQL = "";

for (String subSQL : sqlList) {
constructedSQL += subSQL + " " + delimiter;
}

if(sqlList.size()!=0){
constructedSQL = constructedSQL.substring(0, constructedSQL.length()
- delimiter.length());

}

return constructedSQL;
}





Stack page

7 10 2008

This is my stack page. Opensource tools that I use, find interesting or need to remember will be listed there:

In use (partial list):
http://wicket.apache.org/
http://wicketstuff.org/
http://sourceforge.net/projects/wicketopia/
http://mojo.codehaus.org/cobertura-maven-plugin/
jpa http://java.sun.com/javaee/5/docs/api/javax/persistence/package-summary.html
http://www.hibernate.org/
http://www.springframework.org/
http://browsershots.org/ (when I need to test cross platform browser)
http://geo-google.sourceforge.net/

https://simple-log.dev.java.net/
http://jbehave.org/
JTS / Hibernate spatial

Maven plugin:

http://maven.apache.org/plugin-developers/cookbook/add-svn-revision-to-manifest.html

Images / Art / Icons for applications free via creative commons or similar
http://tango.freedesktop.org/
http://www.everaldo.com/crystal/
http://www.famfamfam.com/lab/icons/silk/
http://www.deviantart.com/
http://www.iconfinder.net/

Tools to help your css:

http://www.cssjuice.com/tools/
http://www.roundz.net/

Interesting:

http://dev.eclipse.org/blogs/kmitov/2009/06/12/jpicus-the-tool-for-java-io-analysis/
http://sixrevisions.com/resources/40-beautiful-free-icon-sets/

http://picocontainer.org/

http://www.jdave.org

http://geoserver.org/
http://code.google.com/p/google-guice/
http://links.sourceforge.net/
http://www.dillo.org/
http://sourceforge.net/projects/protogen/
http://sourceforge.net/projects/qwick/

http://code.google.com/p/liquidform/
J2ME stuff:
https://meapplicationdevelopers.dev.java.net/mobileajax.html

Trouble shooting:

https://visualvm.dev.java.net

Desktop development:

http://publicobject.com/glazedlistsdeveloper/
https://appframework.dev.java.net/

funstuf

http://slick.cokeandcode.com/

jmoneyengine

documentation:

http://repo.exist.com/dist/maestro/1.7.0/BetterBuildsWithMaven.pdf
http://apollo.ucalgary.ca/tlcprojectswiki/index.php/Public/Subversion
http://apollo.ucalgary.ca/tlcprojectswiki/index.php/Public/Project_Versioning__Best_Practices#Build_Versioning

http://books.google.dk/books?id=zGgZ850Aw5gC&pg=PA1&lpg=PA1&dq=Beginning+Ubuntu+Server+Administration&source=bl&ots=6I0rezDNZY&sig=pAR-0kD7PxnlBAY5w0cw98ndWU0&hl=da&ei=SMB6SsPwA4OL-QaDvNVW&sa=X&oi=book_result&ct=result&resnum=4#v=onepage&q=&f=false

Project Stitching Spider

CI : https://hudson.dev.java.net/ / http://continuum.apache.org

Issue : http://jtrac.info/

WIKI: http://www.xwiki.org

SVN:http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91 / http://www.visualsvn.com/server/