Labels

Monday, 29 November 2010

How to add a currency converter to your site

Today, I was faced with an issue that every e-commerce site faces one time or another. I want to create a currency converter that uses data from an online, trusted, accurately updated location. I did my research and decided to share it so you don't have to.

My first stop was at Luma (www.luma.co.nz), at an article titled "Making Currency Conversion Easier for the Web" - (http://www.luma.co.nz/featured/making-currency-conversion-easier-for-the-web/). The article suggests that there are three methods to add a currency converter to your site:

1. Using Webservices.

2. Using an iframe to display a conversion tool provided by another site. The site suggested Google Finance (http://www.google.com/finance/converter?a=100&from=EGP&to=USD) as a candidate for this method. Google Finance provides a clean interface however, if you want to apply the currency changes to all prices on your site instead of just showing a conversion calculator then this is not the answer here.

3. Pull the exchange rates from an external source.

Luma provides a tool for obtaining a copy of the free exchange rate XML feed from the European Central Bank (http://www.ecb.int/stats/exchange/eurofxref/html/index.en.html) and generates either Java script or Ruby for doing conversions.

The idea there is to create a task that runs periodically on your server to refresh your copy of the data.

Although Luma's idea is good and is backed up with a good effort to create these tools, My reluctance to use this idea is due to the fact that it is written in Ruby - which I am no expert of - and so I will be relying on a piece of code that I will have trouble changing.

My other concern here is that we are now relying on an administrative task for executing our data update. I prefer to keep all my business logic inside my code, agree with me or not, I think of the update interval as part of the business logic. So on I go.

My next stop was at thomasknierim.com. They provide source code for a Currency Converter that also uses the XML feed from the European Central Bank to do currency conversions in Java.
The source code is provided and it uses a similar concept as Luma's, it caches the data and provides an update policy and mechanism for managing the data integrity and interface methods for conversion. Brilliant.

Another mechanism to do this without keeping cache would be to use Yahoo Finance. Yahoo Finance provides a way for obtaining conversion data using a URL that provides CSV (Comma Seperated Value).
The CSV is small, easy to parse and is timestamped.

For some reason I am still to figure out, the rates obtained from Yahoo Finance is different data I found on other sites like Oanda (http://www.oanda.com/). Oanda offers a service for publishers, it provides them with an XML or a CSV that is regularly updated. This service costs 200$ per month.

Friday, 22 October 2010

Equniox P2 Update issues and problems - Part 1

The plugins have been downloaded but update didn't take place:

I faced this issue myself for some time. Researching the internet resulted in finding someone who suggest removing the JRE folder. The solution sounded like trying to fix a cracked wall with glue but I tried it and it worked!!

P2 update apparently uses this JRE folder and will regenerate it if you delete it. Removing the JRE folder also implies that the application is now going to use the default JRE. This means that now we have no control over the run level of the application. If our application is using JRE version 1.6 and the default runtime environment is 1.5, then we are at risk that our application will not work.

A college of mine was analysing this issue. He used a packet analyser and discovered something very interesting.

P2 sends a time stamp to the repository location. This time stamp represents the time of creation of the artifacts used for the latest update made by the application.

P2 will make the usual steps for updating (e.g. check the meta-data repository if a later version exist, download that version). But before actual update of the application (or un-install then install to be exact), this is the moment where the use of the time stamp kicks in.

P2 uses this time stamp to make sure that the artifacts downloaded are created after the artifacts already installed (in other words, comparing the time of creation of the artifacts on the repository with the time of creation of the installed artifacts).

So if the platform downloaded artifacts that were created on the same day (or earlier) as the files it already has, then even thou the versions suggests that this update is a later one, P2 will not update.

The other thing we need to take notice of is that the time stamp smallest unit is the day. That means that if the artifacts of the repository are created later that same day, P2 would still refuse to update.

Testing this is rather easy. Change the clock on your PC a couple of days back and create a product. Afterwards, move it back to the current time and create another product (the one we are going to update to). We are going to use the repository created with the second product for the update. You will find that P2 will update smoothly.

In my opinion, this will not cause a problem in an actual production environment because almost never will it happen that we create a product, distribute it then add an update for it that was created on the same day as the product itself!. If this ever happens to you, my advice is wait a day before you put create your update artifacts.

Thanks for reading.

Thursday, 21 October 2010

RCP Headless Auto Update using Equinox P2

The Equinox P2 allows us to add update functionality to our applications. In this post, I am specially exploring headless auto update techniques.

The code in this post is build upon a project in eclipse CVS.

What is Equinox P2?
As per eclipse, "Equinox p2 is a component of the Equinox project. p2 provides a provisioning platform for Eclipse-based applications. ".

P2 is an equinox component that allows you to update your application. There are two types of P2 Updates, using the P2 user interface (UI) similar to the way you update your own eclipse IDE and headless update, which is what this post is about, and allows you to update without user interaction from within your application.

What are repositories?

Repositories are locations (remote or local) where you keep your resources used in the P2 Update. There are two types of repositories:
  • Artifact Repositories, this is where we keep our actual archive files.
  • Meta-Data Repositories, Meta data, by definition, is data describing data. Here what this means is that it has data regarding your implementation (artifacts).
The P2 mechanism will contact the Meta-Data repository to know all the information it needs in order to determine if an update is available and possible. It contacts the artifact repository at the very end just in time of the actual download.

What are IUs (Installable Units)

IU is the smallest update-able unit.

How to use P2 headless update in your application?

1. Add the P2 Plug-ins to the required plug-ins list. Open your manifest file > go to the Dependencies tab > then add each one of the following plugins:
  • org.eclipse.equinox.p2.metadata
  • org.eclipse.equinox.p2.metadata.repository
  • org.eclipse.equinox.p2.artifact.repository
  • org.eclipse.equinox.p2.repository
  • org.eclipse.equinox.p2.extensionlocation
  • org.eclipse.equinox.p2.updatesite
  • org.eclipse.equinox.p2.director
  • org.eclipse.equinox.p2.engine
  • org.eclipse.equinox.p2.core
2. Start the P2 infrastructure, normally the P2 UI does this but since we are doing a headless update we will need to do it ourselves. In your BundleActivator class add these lines:

getBundle("org.eclipse.equinox.p2.exemplarysetup")
.start(Bundle.START_TRANSIENT);
getBundle("org.eclipse.equinox.frameworkadmin.equinox")
.start(Bundle.START_TRANSIENT);
getBundle("org.eclipse.equinox.simpleconfigurator.manipulator")
.start(Bundle.START_TRANSIENT);

3. Start P2 update

final IProfileRegistry profileRegistry =
(IProfileRegistry) ServiceHelper
.getService(Activator.getBundleContext(),
IProfileRegistry.class.getName());

final IProfile profile = profileRegistry.getProfile(IProfileRegistry.SELF);

// We are going to look for updates to all IU's in the profile. A
different query could be used if
// we are looking for updates to
a subset. For example, the p2 UI only looks for updates to
//those
IU's marked with a special property.
final Collector collector = profile.query(InstallableUnitQuery.ANY, new Collector(), null);

final IMetadataRepositoryManager manager = (IMetadataRepositoryManager) ServiceHelper
.getService(Activator.getBundleContext(),IMetadataRepositoryManager.class.getName());

// This will get the artifact repository from P2.inf, we can provide our own URI here instead
// of using P2.inf
URI[] reposToSearch = manager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL);

final IPlanner planner = (IPlanner) ServiceHelper.getService(
Activator.getBundleContext(), IPlanner.class.getName());

// Looking in all known repositories for updates for each IU in the profile
final boolean[] didWeUpdate = new boolean[1];
didWeUpdate[0] = false;

// 1. Load repositories
for (int i = 0; i <>
try {
manager.loadRepository(reposToSearch[i], null);
} catch (ProvisionException e) {
// An error occurred while contacting Repository location.
// Repository Location will be discarded.
continue;
}
}

// 2. Get update list by looking for an IU replacement for each of our IUs
ArrayList iusWithUpdates = new ArrayList();
ArrayList replacementIUs = new ArrayList();

Iterator iter = collector.iterator();
ProvisioningContext pc = new ProvisioningContext(reposToSearch);
while (iter.hasNext()) {
IInstallableUnit iu = (IInstallableUnit) iter.next();
IInstallableUnit[] replacements = planner.updatesFor(iu,pc, null);
if (replacements.length > 0) {
iusWithUpdates.add(iu);
if (replacements.length == 1) {
replacementIUs.add(replacements[0]);
} else {
IInstallableUnit repl = replacements[0];
for (int i = 1; i <>
if (replacements[i].getVersion().compareTo(repl.getVersion()) > 0) {
repl = replacements[i];
}
}
replacementIUs.add(repl);
}
}
}
// Did we find any updates?
if (iusWithUpdates.size() > 0) {
// 3. Build a profile change request and get a provisioning plan
ProfileChangeRequest changeRequest = new ProfileChangeRequest(profile);
// Remove old component
changeRequest.removeInstallableUnits((IInstallableUnit[]) iusWithUpdates
.toArray(new IInstallableUnit[iusWithUpdates.size()]));
// Add new component
changeRequest.addInstallableUnits((IInstallableUnit[]) replacementIUs
.toArray(new IInstallableUnit[replacementIUs.size()]));
// Checking validity of updates
ProvisioningPlan plan = planner.getProvisioningPlan(changeRequest, pc, null);
if (plan.getStatus().getSeverity() == IStatus.CANCEL) {
// User Canceled
}
if (plan.getStatus().getSeverity() != IStatus.ERROR) {
IEngine engine = (IEngine) ServiceHelper.getService(Activator.getBundleContext(), IEngine.class.getName()); // Get artifact repository manager service IArtifactRepositoryManager artifactMgr = (IArtifactRepositoryManager) ServiceHelper.getService(Activator.getBundleContext(), IArtifactRepositoryManager.class.getName());
// 4. Perform the provisioning plan
URI[] artifactRepositories =
artifactMgr
.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL);
pc.setArtifactRepositories(artifactRepositories); IStatus status = engine.perform(profile, new DefaultPhaseSet(), plan.getOperands(), pc, null);
if (status.getSeverity() != IStatus.ERROR) {
didWeUpdate[0] = true;
} }
}

Thanks for reading.

Tuesday, 19 October 2010

Blackbox and Whitebox tests using JUnit

What is the difference between Black box testing and White box testing?
White Box testing aims to test internal methods or part of a component, while Black Box testing aims to test a component, treated as a black box (thus the name) using the public methods provided by this component.

How to Perform Black Box tests?
A JUnit Test Suite (a group of JUnit Test Case s) with a good coverage will test all the public methods provided by a component. Keep in mind that the Black Box test tests the component itself and not it's integration with other component. In order to accomplish that separation, you need to create "mocks" of all components used by your's.

The injection of these mock components can be a little bit tricky if you don't have a public method that does so. In this case the only way for injecting your mock objects will be through Java Reflection as we will discuss later.

How to Perform White Box tests?
As we explained earlier, the White box tests aims at testing specific parts of your components. A well written component that follows Object Oriented will have these specific parts hidden from others outside the component (Encapsulation).

The best way for getting around this is to use Java Reflection to manipulate these parts (usually private methods).

Using Java Reflection for JUnit testing:
It is generally a bad practise to change an access modifier in a method for testing, this violates the contract that should be provided by the component, the component encapsulation and common sense really.

In order to invoke a private method (e.g. in ClassUnderTest imaginary class) we have to use Java Reflection:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
.
.
// Will hold the class types to be sent as parameters to the tested method,
// Leave as null if the method doesn't accept any parameters
Class [] inputClasses= null;
Object[] inputObjects = null;

ClassUnderTest testClass = new ClassUnderTest();

// getDeclaredMethod will return all methods
// (that is including private, public , protected and default)
// getMethod on the other hand, only returns public methods
Method testedMethod = ClassUnderTest.class.getDeclaredMethod("methodName", inputClasses);

// Very important, else you will get an IllegalAccessException
testedMethod.setAccessible(true);

// Assuming the method returns a String, cast as appropriate
String returnValue = (String) testedMethod.invoke(testClass, object);

Thanks for reading.


Friday, 15 October 2010

Getting Stack Trace from Throwables as String

Problem:
We want to get the stack trace of a Throwable (Errors or Exceptions) in a String format.
Why we want that:
We wanted to log it using log4j at the Debug level.

Solution:

1. Use the getStackTrace() method:

This method returns an array of StackTraceElement objects. As per the Java Docs "Each object represents represents a single stack frame. All stack frames except for the one at the top of the stack represent a method invocation. The frame at the top of the stack represents the execution point at which the stack trace was generated. Typically, this is the point at which the throwable corresponding to the stack trace was created."

This way isn't very good for our needs. we just want a String looking like the one you get from call printStackTrace() and in order to do that, we will have to get the exception message using
getMessage() or getLocalizedMessage() and then loop through the StrackTraceElement array to get the trace.

This solution might be good for other uses but definitely not for this one.

2. Read the actual output of printStackTrace() method:

The printStackTrace() method has an overloaded version printStackTrace(PrintWriter s) , this method - as per JavaDocs - "Prints this throwable and its backtrace to the specified print writer".

String getStackTrace(final Throwable pThrowable) {

String stackTrace = null;
StringWriter stringWriter = null;
PrintWriter printWriter = null;

try {
stringWriter = new StringWriter();
printWriter = new PrintWriter(stringWriter);
pThrowable.printStackTrace(printWriter);
stackTrace = stringWriter.getBuffer().toString();
} catch (Throwable t) {
stackTrace = null;
} finally {
if (printWriter != null) {
printWriter.close();
}
}
return stackTrace;
}
This method will return the stack trace in a String format.

Thank you for reading.