Integration Example: Java
Global Services Integration
Ensure you have an account setup. You will need the Username, Password and WSDL location.
Please note: Wherever <LatestWSDLVersion> is shown in Example Code below, please replace this with GlobalServices21a.wsdl.
If you are unsure of any of the details you can contact the helpdesk for more information.
Importing the WSDL (Maven)
There are many different ways of importing a WSDL into your program. Use whichever method you are most familiar with.
This sample code uses JAXWS to import and generate the webservice objects with Maven. An example POM is provided below.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gb</groupId>
<artifactId>idm-globalservices-intergration-example</artifactId>
<name>idm-globalservices-intergration-example</name>
<description>Example of an address lookup.</description>
<packaging>jar</packaging>
<version>1.0</version>
<build>
<resources>
<resource>
<filtering>false</filtering>
<directory>src/main/resources</directory>
</resource>
<resource>
<filtering>false</filtering>
<directory>src/main/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<optimize>true</optimize>
<debug>true</debug>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.8</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<id>Import Idm GlobalServices WS</id>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<packageName>com.gb.idm.ws.globalservices.schema</packageName>
<wsdlFiles>
<wsdlFile><LatestWSDLVersion></wsdlFile>
</wsdlFiles>
<extension>true</extension>
<staleFile>${project.build.directory}/jaxws/stale/wsdl.GlobalServicesWSDL.done</staleFile>
<bindingFiles>
<bindingFile>jaxb-bindings.xml</bindingFile>
</bindingFiles>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-tools</artifactId>
<version>2.1.3</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.gb.GlobalServiceLookup</mainClass>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${pom.url}</url>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>Apache Nexus</id>
<url>https://repository.apache.org/content/repositories/snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>
The <LatestWSDLVersion> file is downloaded and saved into "Project_Root/wsdl/<LatestWSDLVersion>". Upon build JAXWS will generate all the web service objects and place them into "globalservices-alu-integration-example\target\jaxws\wsimport\java".
The IDE may automatically exclude the target directory from the project. Go into the module settings and add the "target\jaxws\wsimport\java" as a source.
Creating the Service
In this example a service layer is created to handle the calls to the web service. First an interface is created.
This helps separate the code out so the implementation can be changed without much consequence.
package main.services;
import com.gb.idm.ws.globalservices.schema.ExecuteCaptureResponse;
public interface GlobalServicesWS {
/**
* Executes an address lookup (will also authenticate if required)
*
* @param postcode Postcode to lookup
* @return ExecuteCaptureResponse with a list of addresses found.
*/
public ExecuteCaptureResponse lookupPostcode(String postcode);
}
protected static final String ENDPOINT = "";
protected static final String USERNAME = "";
protected static final String PASSWORD = "";
protected static final String PROFILE_GUID = "";
private AuthenticationDetails user = new AuthenticationDetails();
These are hard coded values which is not best practice. Consider moving the authentication details to an external location (database, properties file etc...).
In the example code attached, an external class Settings reads the values from an xml file.
The following method is the implementation of the lookupPostcode(); method shown in the Interface class above:
@override
public executecaptureresponse lookuppostcode(string postcode) {
system.out.println("authenticating as: " + this.settings.getidmusername());
// setup the objects to use on the capture request.
executecapturerequest request = new executecapturerequest();
profilerequestcapture profilerequestcapture = new profilerequestcapture();
profilerequestcapturedata profilerequestcapturedata = new profilerequestcapturedata();
// idm options
profilerequestcapture.setconfigurationid(1);
profilerequestcapture.setcustomerreference("samplecode"); profilerequestcapture.setprofileguid(globalserviceswsimpl.matchcode_names_profile_guid);
// add the objects to form a complete request.
request.setprofilerequest(profilerequestcapture);
profilerequestcapture.setrequestdata(profilerequestcapturedata);
idmdatasearchaddress idmdatasearchaddress = new idmdatasearchaddress();
idmdatasearchaddress.setpostcode(postcode);
profilerequestcapturedata.setaddress(idmdatasearchaddress);
profilerequestcapturedata.setoptions(this.getidmaddressoptions());
executecaptureresponse response = this.executecapture(request);
return response;
}
The getSecurityMethod below will attempt an authentication before adding the required username and authenticationToken to the SecurityHeader:
private SecurityHeader getSecurityHeader() {
// Create a new SecurityHeader
SecurityHeader securityHeader = new SecurityHeader();
// Authenticate user if needed.
this.authenticateUser();
// Add the required authentication details to the header.
securityHeader.setAuthenticationToken(this.user.getAuthenticationToken());
securityHeader.setUsername(this.user.getUsername());
return securityHeader;
}
The authenticateUser method will check to see if the user has a valid authenticationToken before validating, if the user has a valid authenticationToken the method will not authenticate against the web service:
public void authenticateUser() {
System.out.println("Checking session...");
// Checks to see if the user has a valid authenticationToken
if (!user.isValid()) {
System.out.println("No valid session - authenticating...");
// Create a new AuthenticateUserRequest
AuthenticateUserRequest request = new AuthenticateUserRequest();
request.setUsername(this.settings.getIdmUsername());
request.setPassword(this.settings.getIdmPassword());
AuthenticateUserResponse response = null;
try {
response = this.getWebService().authenticateUser(request);
} catch (BusinessException exception) {
System.out.println("Business exception.");
// Catch a specific exception and display message
if (exception.getFaultInfo().getDetail().getErrorCode().equals("BE010009")) {
System.out.println("Invalid credentials");
} else {
System.out.println("Business Exception ErrorCode: " + exception.getFaultInfo().getDetail().getErrorCode());
}
} catch (ServiceException e) {
System.out.println("Service exception.");
throw new NoAuthenticateException();
} catch (Exception e) {
System.out.println("Exception.");
throw new NoAuthenticateException();
}
if (response == null) {
throw new NoAuthenticateException();
}
// Create a new AuthenticationDetails and add the response.
this.user = new AuthenticationDetails(response);
if (response != null && response.getAuthenticationTime() != null) {
System.out.println("Authentication successful at: " + response.getAuthenticationTime().toXMLFormat());
}
} else {
System.out.println("Session valid reusing authentication token.");
}
}
Getting the Web Service
The requests are being sent with the this.getWebservice method. This method returns the webservice with the specified endpoint. See the below method:
private IdMGlobalServices getWebService() {
IdMGlobalServices service = null;
try {
// Create a new web service with the endpoint we have supplied.
final IdMGlobalServicesService ws = new IdMGlobalServicesService(
new URL(this.settings.getEndpointUrl()),
new QName("http://gbworld.gb.co.uk/idm-globalservices/messages/21a/", "IdM-GlobalServicesService"));
service = ws.getIdMGlobalServicesSoap11();
} catch (Exception e) {
e.printStackTrace();
}
return service;
}
Managing Authentication Details and Session Tokens
The AuthenticationDetails class contains the username, authenticationToken, authenticationTime and some logic to refresh authenticationDetails and check the validity of the authenticationToken:
package com.gb.util;
import com.gb.idm.ws.globalservices.schema.AuthenticateUserResponse;
import java.util.Date;
public class AuthenticationDetails {
private String username;
private String authenticationToken;
private Date authenticationTime;
private Date sessionExpiryTime;
public AuthenticationDetails() {}
public AuthenticationDetails(AuthenticateUserResponse response) {
this.username = response.getFullUsername();
this.authenticationToken = response.getAuthenticationToken();
this.authenticationTime = response.getAuthenticationTime().toGregorianCalendar().getTime();
this.sessionExpiryTime= response.getSessionExpiryTime().toGregorianCalendar().getTime();
}
public String getUsername() {
return username;
}
public String getAuthenticationToken() {
return authenticationToken;
}
public Date getAuthenticationTime() {
return authenticationTime;
}
public Date getSessionExpiryTime() {
return sessionExpiryTime;
}
public boolean isValid() {
boolean valid = true;
if (this.sessionExpiryTime == null || new Date().after(this.sessionExpiryTime)) {
valid = false;
}
return valid;
}
public void refreshAuthenticationToken(String authenticationToken, Date expiry) {
this.authenticationToken = authenticationToken;
this.sessionExpiryTime = expiry;
}
}
Telephone Integration
The following code will expand on the examples to demonstrate an integration into the Global Telephone validation service.
Sample Code
The telephone lookup method:
private static void doTelephoneLookup() throws Exception {
String mobile = "";
String landline = "";
System.out.println("Enter Mobile: ");
// Readline pauses the application an waits for user input.
mobile = GlobalServiceLookup.READER.readLine();
System.out.println("Enter Landline: ");
// Readline pauses the application an waits for user input.
landline = GlobalServiceLookup.READER.readLine();
ExecuteCaptureResponse response = GlobalServiceLookup.GLOBALSERVICES.lookupTelephone( mobile, landline);
for (ProfileResponseDetails profileResponse : response.getProfileResponse().getProfileResponseDetails()) {
System.out.format("%20s", profileResponse.getComponentAction());
System.out.format("%20s", profileResponse.getComponentStatus() + "\n");
// Check for address results.
if (profileResponse.getCaptureResponse() != null && profileResponse.getCaptureResponse().getResponse() != null) {
for (CaptureResponseData data : profileResponse.getCaptureResponse().getResponse()) {
for (IdmDataAddress address : data.getAddress()) {
System.out.format("%20s", GlobalServiceLookup.LINE_INDENT + "- " + address.getFormattedAddress() + "\n");
}
}
}
// Check for telephone results
if (profileResponse.getValidateResponse() != null && profileResponse.getValidateResponse().getResponse() != null) {
for (ValidateResponseData responseData : profileResponse.getValidateResponse().getResponse()) {
// Show number
System.out.format("%20s", GlobalServiceLookup.LINE_INDENT + "- " + responseData.getInput() + "\n");
// Show Key Value pairs
for (IdmDataItem item : responseData.getValidationCodes().getItem()) {
System.out.format("%20s",
GlobalServiceLookup.LINE_INDENT +
"\t" +
"- " +
item.getKey() +
" = " +
item.getValue() +
"\n");
}
}
}
}
}
This method will call the lookupTelephone method and handle the response to display. The data is output to the console separated by tabs using the GlobalServiceLookup.LINE_INDENT string.
The following is the lookupTelephone() method. It is very similar to the C# sample code.
@Override
public ExecuteCaptureResponse lookupTelephone(final String mobile, final String landline) {
// Setup the objects to use on the ALU.
ExecuteCaptureRequest request = new ExecuteCaptureRequest();
ProfileRequestCapture profileRequestCapture = new ProfileRequestCapture();
ProfileRequestCaptureData profileRequestCaptureData = new ProfileRequestCaptureData();
List<IdmDataCaptureTelephone> telephones = new ArrayList<IdmDataCaptureTelephone>();
IdmDataSearchAddress address = new IdmDataSearchAddress();
// Idm options
profileRequestCapture.setConfigurationId(1);
profileRequestCapture.setCustomerReference("SampleCode");
profileRequestCapture.setProfileGuid(GlobalServicesWSImpl.GLOBAL_TELEPHONE_PROFILE_GUID);
// Add mobile if provided
if (!Strings.isNullOrEmpty(mobile)) {
IdmDataCaptureTelephone phone = new IdmDataCaptureTelephone();
phone.setNumber(mobile);
phone.setType(EnumTelephone.MOBILE);
telephones.add(phone);
}
// Add landline if provided
if (!Strings.isNullOrEmpty(landline)) {
IdmDataCaptureTelephone phone = new IdmDataCaptureTelephone();
phone.setNumber(landline);
phone.setType(EnumTelephone.LANDLINE);
telephones.add(phone);
}
// Add the objects to form a complete request.
request.setProfileRequest(profileRequestCapture);
profileRequestCapture.setRequestData(profileRequestCaptureData);
profileRequestCaptureData.setAddress(address);
profileRequestCaptureData.setOptions(this.getIdmAddressOptions());
profileRequestCaptureData.getTelephone().addAll(telephones);
// Call execute capture.
return this.executeCapture(request);
}
The options for the phone lookup have been put into another method getIdmAddresssOptions().
private IdmRequestOptions getIdmAddressOptions() {
IdmRequestOptions options = new IdmRequestOptions();
options.setAddressSearchLevel(EnumAddressLevel.PREMISE);
options.setCasing(EnumCasing.MIXED);
options.setMaxReturn(10);
options.setOffset(0);
options.setCountryCodeFormat(EnumCountryCodeFormat.ISO_3);
options.setAddressEnvelopeFormat("A3TCP");
return options;
}
It will call the executeCapture() method which can be re-used to do an extended address lookup.
private ExecuteCaptureResponse executeCapture(ExecuteCaptureRequest request) {
// Gets the security header will do an authentication if there is not a valid authentication token.
request.setSecurityHeader(this.getSecurityHeader());
ExecuteCaptureResponse response = null;
try {
// Try calling the webservice
response = this.getWebService().executeCapture(request);
this.user.refreshAuthenticationToken(
response.getSecurityHeader().getAuthenticationToken(),
response.getSecurityHeader().getSessionExpiryTime().toGregorianCalendar().getTime());
} catch (BusinessException exception) {
// Catch a specific exception and display message
if (exception.getFaultInfo().getDetail().getErrorCode().equals("BE010009")) {
System.out.println("Invalid credentials");
} else {
System.out.println("Business Exception ErrorCode: " + exception.getFaultInfo().getDetail().getErrorCode());
}
} catch (ServiceException exception) {
// Service exception show error code and transactionId so it can be relayed to helpdesk.
System.out.println(
"Service exception - " +
exception.getFaultInfo().getDetail().getErrorCode() +
" TransactionGuid: " +
exception.getFaultInfo().getTransactionId()
);
} catch (Exception exception) {
System.out.println("Problem checking details.");
}
return response;
}
The exception handling is done here as we are outputting to the console we do not require access to any GUI objects. This also means the exception handling will work if doing an extended address lookup.
Bank Integration
The following code will expand on the examples to demonstrate an integration into the Bank Account validation service.
Sample Code
The bank account lookup method:
private static void doBankCheck() throws Exception {
System.out.println("Enter short code: ");
final String shortCode = GlobalServiceLookup.READER.readLine();
System.out.println("Enter account number: ");
final String accountNumber = GlobalServiceLookup.READER.readLine();
// WS call
final ExecuteCaptureResponse response = GlobalServiceLookup.GLOBALSERVICES.bankCheck(
shortCode, accountNumber);
// Check for bank results
boolean found = false;
if (response != null
&& response.getProfileResponse() != null
&& response.getProfileResponse().getProfileResponseDetails() != null) {
for (ProfileResponseDetails profileResponse :
response.getProfileResponse().getProfileResponseDetails()) {
if ("Bank Account Validation".equals(profileResponse.getComponentName())) {
if (profileResponse.getComponentStatus() == EnumComponentStatus.SUCCESS) {
if (profileResponse.getValidateResponse() != null &&
profileResponse.getValidateResponse().getResponse() != null &&
!profileResponse.getValidateResponse().getResponse().isEmpty() &&
profileResponse.getValidateResponse().getResponse().get(0) != null &&
profileResponse.getValidateResponse().getResponse().get(0).getValidationCodes() != null &&
profileResponse.getValidateResponse().getResponse().get(0).getValidationCodes().getItem() != null) {
final List<IdmDataItem> items =
profileResponse.getValidateResponse().getResponse().get(0).getValidationCodes().getItem();
for (final IdmDataItem item : items) {
final String line = item.getKey() + ": " + item.getValue();
System.out.format("%20s", GlobalServiceLookup.LINE_INDENT + "- " + line + "\n");
}
} else {
System.out.format("%20s", GlobalServiceLookup.LINE_INDENT +
"- Web Service call successed but no results returned." + "\n");
}
} else {
System.out.format("%20s", GlobalServiceLookup.LINE_INDENT + "- Failure" + "\n");
}
found = true;
break;
}
}
}
if (!found) {
System.out.format("%20s", GlobalServiceLookup.LINE_INDENT + "- " + "Web service failure" + "\n");
}
}
This method will call the doBankCheck() method and handle the response to display. The data is output to the console separated by tabs using the GlobalServiceLookup.LINE_INDENT string.
The following is the bankCheck() method. It is very similar to the C# sample code.
public ExecuteCaptureResponse bankCheck(final String sortCode, final String accountNumber) {
// Setup the objects to use on the GlobalServices.
ExecuteCaptureRequest request = new ExecuteCaptureRequest();
ProfileRequestCapture profileRequestCapture = new ProfileRequestCapture();
ProfileRequestCaptureData profileRequestCaptureData = new ProfileRequestCaptureData();
// Idm options
profileRequestCapture.setConfigurationId(1);
profileRequestCapture.setCustomerReference("SampleCode");
profileRequestCapture.setProfileGuid(GlobalServicesWSImpl.BANK_CHECK_GUID);
final IdMDataCaptureBank dataCapture = new IdMDataCaptureBank();
dataCapture.setAccountNumber(accountNumber);
dataCapture.setSortcode(sortCode);
// Add the objects to form a complete request.
request.setProfileRequest(profileRequestCapture);
profileRequestCapture.setRequestData(profileRequestCaptureData);
profileRequestCaptureData.setOptions(this.getIdmAddressOptions());
profileRequestCaptureData.getBank().add(dataCapture);
// Call execute capture.
return this.executeCapture(request);
}
AddressBase Premium
The following code will expand on the examples to demonstrate an integration into the AddressBase Premium capture service.
Sample Code
The AddressBase Premium lookup method:
private static void doAddressBasePremiumLookup() throws IOException {
String postcode = "";
String building = "";
// Keep trying to get an input for a postcode from user.
while (postcode.isEmpty()) {
System.out.println("Enter postcode: ");
// Readline pauses the application an waits for user input.
postcode = GlobalServiceLookup.READER.readLine();
}
// Ask once for a building from user.
System.out.println("Enter building: ");
// Readline pauses the application an waits for user input.
building = GlobalServiceLookup.READER.readLine();
// WS call
final ExecuteCaptureResponse response = GlobalServiceLookup.GLOBALSERVICES.addressBasePremiumLookup(postcode, building);
// Check for AddressBasePremium results
boolean found = false;
StringBuilder sbOutput = new StringBuilder();
if (response != null
&& response.getProfileResponse() != null
&& response.getProfileResponse().getProfileResponseDetails() != null) {
for (ProfileResponseDetails profileResponse : response.getProfileResponse().getProfileResponseDetails()) {
if ("AddressBase Premium".equals(profileResponse.getComponentName())) {
sbOutput.append(profileResponse.getComponentStatus().toString() + System.lineSeparator());
if (profileResponse.getComponentStatus() == EnumComponentStatus.SUCCESS) {
found = true;
}
if (profileResponse.getCaptureResponse() != null
&& profileResponse.getCaptureResponse().getResponse() != null
&& !profileResponse.getCaptureResponse().getResponse().isEmpty()) {
for (CaptureResponseData captureResponseData : profileResponse.getCaptureResponse().getResponse()) {
if (captureResponseData.getAddress() != null
&& !captureResponseData.getAddress().isEmpty()) {
for (IdmDataAddress singleAddress : captureResponseData.getAddress()) {
String formatttedAddress = singleAddress.getFormattedAddress();
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "FormattedAddress:" +
formatttedAddress + System.lineSeparator());
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "OSAPR:" +
singleAddress.getApOSAPR() + System.lineSeparator());
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "Al2Toid:" +
singleAddress.getOsAl2Toid() + System.lineSeparator());
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "ItnToid:" +
singleAddress.getOsItnToid() + System.lineSeparator());
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "TopoToid:" +
singleAddress.getOsTopoToid() + System.lineSeparator());
IdmDataBLPU blpu = singleAddress.getBlpu();
if (null != blpu) {
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "BLPU.State:" + blpu.getBlpuState() + System.lineSeparator());
if (null != blpu.getBlpuStartDate()) {
IdmDataDate startDate = blpu.getBlpuStartDate();
if (null != startDate) {
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "BLPU.StartDate:" +
startDate.getYear() + "-" + startDate.getMonth() + "-" + startDate.getDay() +
System.lineSeparator());
}
}
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "BLPU.LogicalStatus:" +
blpu.getBlpuLogicalStatus() + System.lineSeparator());
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "BLPU.Easting:" +
blpu.getEasting() + System.lineSeparator());
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "BLPU.Northing:" +
blpu.getNorthing() + System.lineSeparator());
}
IdmDataLPI lpi = singleAddress.getLpi();
if (null != lpi) {
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "LPI.Key:" +
lpi.getLpiKey() + System.lineSeparator());
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "LPI.Level:" +
lpi.getLevel() + System.lineSeparator());
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "LPI.Language:" +
lpi.getLpiLanguage() + System.lineSeparator());
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "LPI.LogicalStatus:" +
lpi.getLpiLogicalStatus() + System.lineSeparator());
}
}
}
}
}
}
}
// display
System.out.print(sbOutput.toString());
}
if (!found) {
System.out.format("%20s", GlobalServiceLookup.LINE_INDENT + "- " + "Web service failure" + "\n");
}
}
This method calls the doAddressBasePremiumLookup() method and handles the response to display. The data is output to the console separated by tabs using the GlobalServiceLookup.LINE_INDENT string.
The following is the addressBasePremiumLookup() method. It is very similar to the C# sample code.
public ExecuteCaptureResponse addressBasePremiumLookup(final String postcode, final String building) {
// Setup the objects to use on the capture request.
ExecuteCaptureRequest request = new ExecuteCaptureRequest();
ProfileRequestCapture profileRequestCapture = new ProfileRequestCapture();
ProfileRequestCaptureData profileRequestCaptureData = new ProfileRequestCaptureData();
// Idm options
profileRequestCapture.setConfigurationId(1);
profileRequestCapture.setCustomerReference("SampleCode");
profileRequestCapture.setProfileGuid(GlobalServicesWSImpl.ADDRESSBASE_PREMIUM_PROFILE_GUID);
// Add the objects to form a complete request.
request.setProfileRequest(profileRequestCapture);
profileRequestCapture.setRequestData(profileRequestCaptureData);
IdmDataSearchAddress idmDataSearchAddress = new IdmDataSearchAddress();
idmDataSearchAddress.setPostCode(postcode);
// building is optional
if ((null != building) && (0 < building.trim().length())) {
idmDataSearchAddress.setBuilding(building);
}
profileRequestCaptureData.setAddress(idmDataSearchAddress);
profileRequestCaptureData.setOptions(this.getIdmAddressOptions());
// Call execute capture.
return this.executeCapture(request);
}
Matchcode Names
The following code will expand on the examples to demonstrate an integration into the Matchcode Names capture service.
Sample Code
The following Names lookup method formats the results with \t (tab) to make them more human readable:
private static void doNameSearching() throws IOException {
System.out.println("Note: Not all fields are required.");
final Person person = new Person();
System.out.println("Enter firstname: ");
person.setFirstName(GlobalServiceLookup.READER.readLine());
System.out.println("Enter lastname: ");
person.setLastName(GlobalServiceLookup.READER.readLine());
System.out.println("Date of birth: ");
System.out.println("Enter day: ");
person.getDateOfBirth().setDay(GlobalServiceLookup.READER.readLine());
System.out.println("Enter month: ");
person.getDateOfBirth().setMonth(GlobalServiceLookup.READER.readLine());
System.out.println("Enter year: ");
person.getDateOfBirth().setYear(GlobalServiceLookup.READER.readLine());
System.out.println("Enter building number or name: ");
person.getAddress().setBuilding(GlobalServiceLookup.READER.readLine());
System.out.println("Enter postcode: ");
person.getAddress().setPostcode(GlobalServiceLookup.READER.readLine());
// WS call
final ExecuteCaptureResponse response = GlobalServiceLookup.GLOBALSERVICES.nameSearch(person);
boolean found = false;
if (response != null
&& response.getProfileResponse() != null
&& response.getProfileResponse().getProfileResponseDetails() != null) {
for (ProfileResponseDetails profileResponse : response.getProfileResponse().getProfileResponseDetails()) {
if ("Matchcode Edited Electoral Roll Names".equals(profileResponse.getComponentName())) {
if (profileResponse.getComponentStatus() == EnumComponentStatus.SUCCESS) {
System.out.println("Found results:");
for (CaptureResponseData captureResponse : profileResponse.getCaptureResponse().getResponse()) {
for (IdmDataAddress idmDataAddress : captureResponse.getAddress()) {
int peopleFound = 0;
if (idmDataAddress.getPersons() != null &&
idmDataAddress.getPersons().getPerson() != null) {
peopleFound = idmDataAddress.getPersons().getPerson().size();
}
System.out.println(peopleFound + " at the following address:");
System.out.println("\t" + idmDataAddress.getFormattedAddress());
System.out.println("\tPeople:");
if (peopleFound > 0) {
for (IdmDataPerson returnedPerson : idmDataAddress.getPersons().getPerson()) {
System.out.println("\t\t" + "Firstname:\t" +
returnedPerson.getFirstname());
System.out.println("\t\t" + "Middlename:\t" +
returnedPerson.getMiddlename());
System.out.println("\t\t" + "Lastname:\t" +
returnedPerson.getLastname());
System.out.println("\t\t" + "Gender:\t\t" +
returnedPerson.getGender());
System.out.println("\t\t" + "DOB:\t\t" +
Formatter.getFormattedDate(returnedPerson.getDateOfBirth()));
System.out.println(" ");
}
}
found = true;
}
}
}
}
}
}
if (!found) {
System.out.format("%20s", GlobalServiceLookup.LINE_INDENT + "- " + "Web service failure" + "\n");
}
}
This shows the construction of the request:
@Override
public ExecuteCaptureResponse nameSearch(final Person person) {
// Setup the objects to use on the capture request.
ExecuteCaptureRequest request = new ExecuteCaptureRequest();
ProfileRequestCapture profileRequestCapture = new ProfileRequestCapture();
ProfileRequestCaptureData profileRequestCaptureData = new ProfileRequestCaptureData();
// Idm options
profileRequestCapture.setConfigurationId(1);
profileRequestCapture.setCustomerReference("SampleCode");
profileRequestCapture.setProfileGuid(GlobalServicesWSImpl.MATCHCODE_NAMES_PROFILE_GUID);
// Add the objects to form a complete request.
request.setProfileRequest(profileRequestCapture);
profileRequestCapture.setRequestData(profileRequestCaptureData);
IdmDataSearchAddress idmDataSearchAddress = new IdmDataSearchAddress();
idmDataSearchAddress.setFreeFormatAddress(person.getAddress().getFreeFormattedAddress());
IdmDataCapturePerson wsPerson = new IdmDataCapturePerson();
wsPerson.setFirstname(person.getFirstName());
wsPerson.setLastname(person.getLastName());
IdmDataDateWithRange dateOfBirth = new IdmDataDateWithRange();
if (person.getDateOfBirth().hasValidDob()) {
dateOfBirth.setDay(person.getDateOfBirth().getIntDay());
dateOfBirth.setMonth(person.getDateOfBirth().getIntMonth());
dateOfBirth.setYear(person.getDateOfBirth().getIntYear());
}
if (person.getAddress().hasAddress()) {
idmDataSearchAddress.setFreeFormatAddress(person.getAddress().getFreeFormattedAddress());
}
wsPerson.setDateOfBirth(dateOfBirth);
IdmDataArrayOfCapturePerson arrayOfCapturePerson = new IdmDataArrayOfCapturePerson();
idmDataSearchAddress.setPersons(arrayOfCapturePerson);
idmDataSearchAddress.getPersons().getPerson().add(wsPerson);
profileRequestCaptureData.setAddress(idmDataSearchAddress);
profileRequestCaptureData.setOptions(this.getIdmAddressOptions());
return this.executeCapture(request);
}
The method uses a placeholder object for the person. It has some utility methods that help with the creation of the request. The following method checks the date for a valid input:
public boolean hasValidDob() {
try {
Integer.parseInt(this.getDay());
Integer.parseInt(this.getMonth());
Integer.parseInt(this.getYear());
} catch (NumberFormatException e) {
System.out.println("Invalid DOB continuing search without.");
return false;
}
return true;
}
Matchcode Premium
Matchcode Premium allows the user to lookup consented telephone numbers for an individual, and also lookup references on social media.
Sample code
The sample code shows how to request the person information, and how to request the type of search required (the social flow type).
private static void doMatchcodePremiumSearching() throws IOException {
String postcode = "";
String building = "";
String firstName = "";
String lastName = "";
String email = "";
// Keep trying to get an input for a postcode from user.
while (postcode.isEmpty()) {
System.out.println("Enter postcode: ");
// Readline pauses the application an waits for user input.
postcode = GlobalServiceLookup.READER.readLine();
}
// Ask once for a building from user.
System.out.println("Enter building: ");
// Readline pauses the application an waits for user input.
building = GlobalServiceLookup.READER.readLine();
// Ask once for a firstName from user.
System.out.println("Enter first name: ");
// Readline pauses the application an waits for user input.
firstName = GlobalServiceLookup.READER.readLine();
// Ask once for a lastName from user.
System.out.println("Enter last name: ");
// Readline pauses the application an waits for user input.
lastName = GlobalServiceLookup.READER.readLine();
final Person person = new Person();
person.setLastName(lastName);
person.setFirstName(firstName);
person.getAddress().setBuilding(building);
person.getAddress().setPostcode(postcode);
// Ask once for an email from user.
System.out.println("Enter email address: ");
// Readline pauses the application an waits for user input.
email = GlobalServiceLookup.READER.readLine();
// request flowType
EnumMatchcodePremiumSocialFlowType socialFlowType = EnumMatchcodePremiumSocialFlowType.APPEND;
System.out.println("Select flow type:");
System.out.println(" a - APPEND (default)");
System.out.println(" s - SOCIAL");
System.out.print("Enter selection: ");
String userInput = GlobalServiceLookup.READER.readLine();
if(userInput.equalsIgnoreCase("s")) {
socialFlowType = EnumMatchcodePremiumSocialFlowType.SOCIAL;
}
System.out.println("Using flow type => "+socialFlowType.toString());
boolean fetchConsented = true;
if(socialFlowType==EnumMatchcodePremiumSocialFlowType.APPEND) {
fetchConsented = true;
}
// WS call
final ExecuteCaptureResponse response = GlobalServiceLookup.GLOBALSERVICES.matchcodePremiumSearch(
person, email, socialFlowType, fetchConsented);
// Check for AddressBasePremium results
boolean found = false;
StringBuilder sbOutput = new StringBuilder();
if (response != null
&& response.getProfileResponse() != null
&& response.getProfileResponse().getProfileResponseDetails() != null) {
for (ProfileResponseDetails profileResponse : response.getProfileResponse().getProfileResponseDetails()) {
if ("Matchcode Premium".equals(profileResponse.getComponentName())) {
sbOutput.append(profileResponse.getComponentStatus().toString() + System.lineSeparator());
if (profileResponse.getComponentStatus() == EnumComponentStatus.SUCCESS) {
found = true;
}
if (profileResponse.getCaptureResponse() != null
&& profileResponse.getCaptureResponse().getResponse() != null
&& !profileResponse.getCaptureResponse().getResponse().isEmpty()) {
for (CaptureResponseData captureResponseData : profileResponse.getCaptureResponse().getResponse()) {
if (captureResponseData.getAddress() != null
&& !captureResponseData.getAddress().isEmpty()) {
for (IdmDataAddress singleAddress
: captureResponseData.getAddress()) {
String formatttedAddress = singleAddress.getFormattedAddress();
sbOutput.append(GlobalServiceLookup.LINE_INDENT +
"- " + "FormattedAddress:" +
formatttedAddress +
System.lineSeparator());
if((null!=singleAddress.getPersons()) &&
(null!=singleAddress.getPersons().getPerson())) {
for(IdmDataCapturePerson singlePerson
: singleAddress.getPersons().getPerson()) {
sbOutput.append("\t\t" +
"Firstname:\t" + singlePerson.getFirstname() +
System.lineSeparator());
sbOutput.append("\t\t" + "Middlename:\t" +
singlePerson.getMiddlename() +
System.lineSeparator());
sbOutput.append("\t\t" + "Lastname:\t" +
singlePerson.getLastname() +
System.lineSeparator());
sbOutput.append("\t\t" + "Gender:\t\t" +
singlePerson.getGender() +
System.lineSeparator());
sbOutput.append("\t\t" + "DOB:\t\t" +
Formatter.getFormattedDate(singlePerson.getDateOfBirth()) +
System.lineSeparator());
if ((null != singlePerson.getConsentedEmails()) &&
(0 < singlePerson.getConsentedEmails().size())) {
for (IdmDataSourcedValue idmDataSourcedValue
: singlePerson.getConsentedEmails()) {
sbOutput.append("\t\t" +
"Email:\t" +
idmDataSourcedValue.getValue() +
System.lineSeparator());
}
}
if ((null != singlePerson.getConsentedLandlines()) &&
(0 < singlePerson.getConsentedLandlines().size())) {
for (IdmDataSourcedValue idmDataSourcedValue
: singlePerson.getConsentedLandlines()) {
sbOutput.append("\t\t" +
"Landline:\t" +
idmDataSourcedValue.getValue() +
System.lineSeparator());
}
}
if ((null != singlePerson.getConsentedMobiles()) &&
(0 < singlePerson.getConsentedMobiles().size())) {
for (IdmDataSourcedValue idmDataSourcedValue
: singlePerson.getConsentedMobiles()) {
sbOutput.append("\t\t" +
"Mobile:\t" +
idmDataSourcedValue.getValue() +
System.lineSeparator());
}
}
if ((null != singlePerson.getAdditionalItems()) &&
(null!= singlePerson.getAdditionalItems().getItem()) &&
(0 < singlePerson.getAdditionalItems().getItem().size())) {
for(IdmDataItem idmDataItem
: singlePerson.getAdditionalItems().getItem()) {
sbOutput.append("\t\t" +
idmDataItem.getKey() +
":\t" +
idmDataItem.getValue() +
System.lineSeparator());
}
}
sbOutput.append(" ");
}
}
}
}
if((null!=captureResponseData.getGroupedRelatedData()) &&
(0 < captureResponseData.getGroupedRelatedData().size())) {
for(IdmDataAdditionalDataGroup idmDataAdditionalDataGroup
: captureResponseData.getGroupedRelatedData()) {
String groupName = idmDataAdditionalDataGroup.getName();
sbOutput.append("\t\t" + groupName +System.lineSeparator());
List<IdmDataItem> listOfGroupDataItem = idmDataAdditionalDataGroup.getItem();
if((null!=listOfGroupDataItem) && (0<listOfGroupDataItem.size())) {
for(IdmDataItem idmDataItem : listOfGroupDataItem) {
sbOutput.append("\t\t\t" +
idmDataItem.getKey() +
":\t" +
idmDataItem.getValue() +
System.lineSeparator());
}
}
}
}
}
}
}
}
// display
System.out.print(sbOutput.toString());
}
if (!found) {
System.out.format("%20s", GlobalServiceLookup.LINE_INDENT + "- " + "Web service failure" + "\n");
}
}
Information from social media is returned in the IdmDataAdditionalDataGroup data structure, which can be pared as shown above.
The actual search requires additional parameters, which for convenience are prescribed in the sample code to limit the amount of user input required.
protected static final EnumMatchcodePremiumSocialType
MATCHCODE_PREMIUM_SOCIAL_TYPE = EnumMatchcodePremiumSocialType.SOCIAL_AUTOMATIC;
protected static final int
MATCHCODE_PREMIUM_SOCIAL_TOTAL = 5;
protected static final EnumMatchcodePremiumConsentedType
MATCHCODE_PREMIUM_CONSENTED_TYPE = EnumMatchcodePremiumConsentedType.ANY;
protected static final int
MATCHCODE_PREMIUM_CONSENTED_TOTAL = 5;
The matchcodePremiumSearch() method:
@Override
public ExecuteCaptureResponse matchcodePremiumSearch(
final Person person,
final String email,
EnumMatchcodePremiumSocialFlowType socialFlowType,
boolean fetchConsented) {
// Setup the objects to use on the capture request.
ExecuteCaptureRequest request = new ExecuteCaptureRequest();
ProfileRequestCapture profileRequestCapture = new ProfileRequestCapture();
ProfileRequestCaptureData profileRequestCaptureData = new ProfileRequestCaptureData();
// Idm options
profileRequestCapture.setConfigurationId(1);
profileRequestCapture.setCustomerReference("SampleCode");
profileRequestCapture.setProfileGuid(GlobalServicesWSImpl.MATCHCODE_PREMIUM_PROFILE_GUID);
// Add the objects to form a complete request.
request.setProfileRequest(profileRequestCapture);
profileRequestCapture.setRequestData(profileRequestCaptureData);
IdmDataSearchAddress idmDataSearchAddress = new IdmDataSearchAddress();
idmDataSearchAddress.setFreeFormatAddress(person.getAddress().getFreeFormattedAddress());
IdmDataCapturePerson wsPerson = new IdmDataCapturePerson();
wsPerson.setFirstname(person.getFirstName());
wsPerson.setLastname(person.getLastName());
idmDataSearchAddress.setPostCode((person.getAddress().getPostcode()));
idmDataSearchAddress.setBuilding((person.getAddress().getBuilding()));
IdmDataArrayOfCapturePerson arrayOfCapturePerson = new IdmDataArrayOfCapturePerson();
idmDataSearchAddress.setPersons(arrayOfCapturePerson);
idmDataSearchAddress.getPersons().getPerson().add(wsPerson);
profileRequestCaptureData.setAddress(idmDataSearchAddress);
// email
if(!email.isEmpty()) {
profileRequestCaptureData.getEmail().add(email);
}
// additional data
IdmDataArrayAdditionalData idmDataArrayAdditionalData = new IdmDataArrayAdditionalData();
List<IdmDataItem> listOfAdditionalDataItem = idmDataArrayAdditionalData.getItem();
// CONSENTED
IdmDataItem dataItemConsented = new IdmDataItem();
dataItemConsented.setKey("CONSENTED");
dataItemConsented.setValue(fetchConsented ? "Yes" : "No");
listOfAdditionalDataItem.add(dataItemConsented);
// FLOW_TYPE
IdmDataItem dataItemFlowType = new IdmDataItem();
dataItemFlowType.setKey("FLOW_TYPE");
dataItemFlowType.setValue(socialFlowType.toString());
listOfAdditionalDataItem.add(dataItemFlowType);
// CONSENTED_TYPE
IdmDataItem dataItemConsentedType = new IdmDataItem();
dataItemConsentedType.setKey("CONSENTED_TYPE");
dataItemConsentedType.setValue(MATCHCODE_PREMIUM_CONSENTED_TYPE.toString());
listOfAdditionalDataItem.add(dataItemConsentedType);
// CONSENTED_TOTAL
IdmDataItem dataItemConsentedTotal = new IdmDataItem();
dataItemConsentedTotal.setKey("CONSENTED_TOTAL");
dataItemConsentedTotal.setValue(Integer.toString(MATCHCODE_PREMIUM_CONSENTED_TOTAL));
listOfAdditionalDataItem.add(dataItemConsentedTotal);
// SOCIAL_REQUEST_ACTION
IdmDataItem dataItemSocialRequestAction = new IdmDataItem();
dataItemSocialRequestAction.setKey("SOCIAL_REQUEST_ACTION");
dataItemSocialRequestAction.setValue(MATCHCODE_PREMIUM_SOCIAL_TYPE.toString());
listOfAdditionalDataItem.add(dataItemSocialRequestAction);
// SOCIAL_EMAIL_TOTAL
IdmDataItem dataItemSocialEmailTotal = new IdmDataItem();
dataItemSocialEmailTotal.setKey("SOCIAL_EMAIL_TOTAL");
dataItemSocialEmailTotal.setValue(Integer.toString(MATCHCODE_PREMIUM_SOCIAL_TOTAL));
listOfAdditionalDataItem.add(dataItemSocialEmailTotal);
profileRequestCaptureData.setAdditionalData(idmDataArrayAdditionalData);
profileRequestCaptureData.setOptions(this.getIdmPremiumOptions());
return this.executeCapture(request);
}
MatchcodePremium requires slightly different options from a simple address or telephone lookup - in particular the search type must be set to REGISTER.
private IdmRequestOptions getIdmPremiumOptions() {
IdmRequestOptions options = new IdmRequestOptions();
options.setAddressSearchLevel(EnumAddressLevel.PREMISE);
options.setAddressSearchType(EnumAddressSearchType.REGISTER);
options.setCasing(EnumCasing.MIXED);
options.setMaxReturn(10);
options.setOffset(0);
options.setAddressEnvelopeFormat("A3TCP");
return options;
}
Exception Handling
The exception handling is done here as we are outputting to the console we do not require access to any GUI objects. This also means the exception handling will work if doing an extended address lookup.
private ExecuteCaptureResponse executeCapture(ExecuteCaptureRequest request) {
// Gets the security header will do an authentication if there is not a valid authentication token.
request.setSecurityHeader(this.getSecurityHeader());
ExecuteCaptureResponse response = null;
try {
// Try calling the webservice
response = this.getWebService().executeCapture(request);
this.user.refreshAuthenticationToken(
response.getSecurityHeader().getAuthenticationToken(),
response.getSecurityHeader().getSessionExpiryTime().toGregorianCalendar().getTime());
} catch (BusinessException exception) {
// TODO: Handle exception
// Catch a specific exception and display message
if (exception.getFaultInfo().getDetail().getErrorCode().equals("BE010009")) {
System.out.println("Invalid credentials");
} else {
System.out.println("Business Exception ErrorCode: " + exception.getFaultInfo().getDetail().getErrorCode());
}
} catch (ServiceException exception) {
// TODO: Handle exception
// Service exception show error code and transactionId so it can be relayed to helpdesk.
System.out.println("Service exception - "
+ exception.getFaultInfo().getDetail().getErrorCode()
+ " TransactionGuid: "
+ exception.getFaultInfo().getTransactionId());
} catch (Exception exception) {
// TODO: Handle exception
System.out.println("Problem checking details.");
}
return response;
}
Project Source Code
Download the source code here: idm-globalservices-integration-example
PowerSearch REST Integration
Ensure you have an account setup. You will need the Username and Password
If you are unsure of any of the details you can contact the helpdesk for more information.
Creating the Application
Next, we will take a look at several key parts of the Powersearch REST Client Application.
Service Layer (REST Client)
In this example a service layer is created to handle the calls to the REST Web Service. First an interface is created.
This helps separate the code out so the implementation can be changed without much consequence. For instance, we will provide an implementation of a Rest Client using a concrete technology (Apache HttpClient), but the interface operations might be implemented by using any other technology.
Next, the code for this Interface:
public interface IPowersearchRestService {
/**
* Communicate to the server to perform the GlobalAddress Operation
*
* @param country
* @param input
* @param sessionKey
* @param format
* @return
*/
ClientResponse<GlobalResponse> getGlobalAddress(String country, String input, String sessionKey,
String format);
/**
* Communicate to the server to perform the Geocode Operation
*
* @param country
* @param input
* @return
*/
ClientResponse<GlobalResponse> getGeocode(String country, String input);
}
As displayed, the Service Client Interface offers two operations to be implemented. These are the same as those offered Powersearch REST WebService.
The following code is the implementation for the two Service Interface Methods
public class PowersearchRestService implements IPowersearchRestService {
private static final String JSON_FORMAT = "application/json";
private static final String XML_FORMAT = "application/xml";
private Settings settings;
public PowersearchRestService(Settings settings) {
this.settings = settings;
}
@Override
public ClientResponse<GlobalResponse> getGlobalAddress(String country, String input, String sessionKey,
String format) {
Map<String, String> params = new HashMap<>();
params.put("address", input);
if (sessionKey != null) {
params.put("sessionkey", sessionKey);
}
if (format != null) {
params.put("format", format);
}
String powerSearchURL = settings.getUrl();
// Add the countryCode to the URL
powerSearchURL = new StringBuffer(powerSearchURL).append("/").append(country).toString();
HttpResponse httpResponse = null;
try {
httpResponse = getServerResponse(powerSearchURL, params);
}
catch (IOException e) {
throw new RuntimeException("Error when connecting to the server", e);
}
GlobalResponse response = deserializeToObject(httpResponse, settings.getAcceptFormat(), GlobalResponse.class);
return new ClientResponse<GlobalResponse>(response, httpResponse.getStatusLine().getStatusCode());
}
@Override
public ClientResponse<GlobalResponse> getGeocode(String country, String input) {
Map<String, String> params = new HashMap<>();
params.put("address", input);
String powerSearchURL = settings.getUrl();
// Add the countryCode to the URL
powerSearchURL = new StringBuffer(powerSearchURL).append("/").append(country).append("/").append("geo").toString();
HttpResponse httpResponse = null;
try {
httpResponse = getServerResponse(powerSearchURL, params);
}
catch (IOException e) {
throw new RuntimeException("Error when connecting to the server", e);
}
GlobalResponse response = deserializeToObject(httpResponse, settings.getAcceptFormat(), GlobalResponse.class);
return new ClientResponse<GlobalResponse>(response, httpResponse.getStatusLine().getStatusCode());
}
/**
* Perform an Http Request to the Rest Server. It uses the Apache HttpClient library to do it.
*
* @param httpGetQuery
* @param params
* @return
* @throws IOException
*/
private HttpResponse getServerResponse(String httpGetQuery,
Map<String, String> params) throws IOException {
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(settings.getIdmUsername(), settings.getIdmPassword());
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();
HttpGet request = new HttpGet(buildHttpGetURL(httpGetQuery, params));
request.addHeader("Accept", settings.getAcceptFormat());
HttpResponse response = client.execute(request);
return response;
}
/**
* Compose a URL to perform a GET Http Method
*
* @param httpGetQuery
* @param params
* @return
* @throws IOException
*/
private String buildHttpGetURL(String httpGetQuery,
Map<String, String> params) throws IOException {
StringBuffer sb = new StringBuffer(httpGetQuery);
if (params != null) {
if (params.size() > 0) {
sb.append("?");
}
for (Map.Entry<String, String> entry : params.entrySet()) {
sb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(),"UTF-8"));
sb.append("&");
}
}
return sb.toString();
}
/**
* Given an HttpResponse, deserialize the content to an object
*
* @param httpResponse
* @param format
* @param clazz
* @return
*/
private <T> T deserializeToObject(HttpResponse httpResponse, String format, Class<T> clazz) {
T response = null;
if (format.equalsIgnoreCase(JSON_FORMAT)) {
try {
ObjectMapper mapper = new ObjectMapper();
response = mapper.readValue(httpResponse.getEntity().getContent(), clazz);
}
catch (Exception e) {
throw new RuntimeException("Error when parsing the Response JSON", e);
}
}
else if (format.equalsIgnoreCase(XML_FORMAT)) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
response = (T) jaxbUnmarshaller.unmarshal(httpResponse.getEntity().getContent());
}
catch (Exception e) {
throw new RuntimeException("Error when parsing the Response XML", e);
}
}
return response;
}
}
The getGlobalAddress method performs the Powersearch REST Service Operation called GlobalAddress by composing the URL, adding the parameters and connecting to the Server. The parameters must be within the URL since the REST operation just allows HTTP GET Requests. The method returns ClientResponse, which contains an object full of data and a status code representing the HTTP Response Status.
The getGeocode method performs the Powersearch REST Service Operation called Geocode by composing the URL, adding the parameters and connecting to the Server. Again, the parameters must be within the URL since the this REST operation just allows HTTP GET Requests. The method returns ClientResponse, which contains an object full of data and a status code representing the HTTP Response Status.
Some non-public methods are added to the Service Implementation such as the one in charge of connecting to the Server and getting a HTTP Response (implemented by Apache HttpClient library) and the one de-serializing the XML or JSON Response from the Server into a known Java Object. We'll see this process below
This process is shown below.
Response Deserialization
The PowerSearch REST WebService returns the requested information either in XML or JSON format. This depends on the "Accept" header parameter value. To deal with that information in the Client Application it's highly recommended to de-serialize the chunk of characters (XML or JSON) into some Data Transfer Objects. This makes easier work with the data.
To de-serialize XML or JSON into Objects we need two things: A process to fill the Objects with data and the Objects to be filled. Keeping in mind the information structure returned by the Service, the Data Transfer Objects created to allocate it are as follows:
public class GlobalResponse {
@XmlElement(name = "sessionData")
private SessionData sessionData;
@XmlElement(name = "matches")
private List<String> matches = new ArrayList<String>();
@XmlElement(name = "information")
private String information;
@XmlElement(name="address")
private PowerSearchAddress address;
/**
* No information required.
*/
public GlobalResponse() {
}
/**
*
* @param sessionData
* SessionData
*/
public GlobalResponse(final SessionData sessionData) {
this.sessionData = sessionData;
}
/**
*
* @param information
* String
*/
public GlobalResponse(final String information) {
this.information = information;
}
/**
*
* @param matches
* List
* @param sessionData
*/
public GlobalResponse(final List<String> matches, final SessionData sessionData) {
this.matches = matches;
this.sessionData = sessionData;
}
/**
*
* @return List
*/
public List<String> getMatches() {
return matches;
}
/**
* Information that could be useful to the client.
*
* @return String
*/
public String getInformation() {
return information;
}
public SessionData getSessionData() {
return sessionData;
}
/**
* GeoInformation
* @return
*/
public PowerSearchAddress getAddress() {
return address;
}
public void setAddress(PowerSearchAddress address) {
this.address = address;
}
}
public class PowerSearchAddress {
private String freeFormat;
@XmlElement(name = "easting")
private String easting;
@XmlElement(name = "northing")
private String northing;
@XmlElement(name = "latitude")
private String latitude;
@XmlElement(name = "longitude")
private String longitude;
public String getFreeFormat() {
return freeFormat;
}
public void setFreeFormat(String freeFormat) {
this.freeFormat = freeFormat;
}
public String getEasting() {
return easting;
}
public void setEasting(String easting) {
this.easting = easting;
}
public String getNorthing() {
return northing;
}
public void setNorthing(String northing) {
this.northing = northing;
}
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
}
public class SessionData {
private String sessionKey;
private Date sessionCommencement;
private int numberOfSessionTransactions;
@XmlElement
public String getSessionKey() {
return sessionKey;
}
@XmlElement
@JsonFormat(shape=Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone="GB")
public Date getSessionCommencement() {
return sessionCommencement;
}
/**
*
* @return int
*/
@XmlElement
public int getNumberOfSessionTransactions() {
return numberOfSessionTransactions;
}
}
The above Data Transfer Object definitions are able to store all the information returned by Powersearch.
All the classes include some annotations such as @XmlElement or @JsonAutoDetect, whose purpose is to guide tools to fill the objects with information from either XML or JSON.
Once we have the Data Transfer Object classes, now it's time to fill these Objects by using some tools. In the case of XML, the provided sample code uses JAXB to de-serialize the XML data. In the case of JSON, the provided sample code uses Jackson to do the same for the JSON data. Next is the concrete code (seen before in the Service Implementation) using the tools:
private <T> T deserializeToObject(HttpResponse httpResponse, String format, Class<T> clazz) {
T response = null;
if (format.equalsIgnoreCase(JSON_FORMAT)) {
try {
ObjectMapper mapper = new ObjectMapper();
response = mapper.readValue(httpResponse.getEntity().getContent(), clazz);
}
catch (Exception e) {
throw new RuntimeException("Error when parsing the Response JSON", e);
}
}
else if (format.equalsIgnoreCase(XML_FORMAT)) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
response = (T) jaxbUnmarshaller.unmarshal(httpResponse.getEntity().getContent());
}
catch (Exception e) {
throw new RuntimeException("Error when parsing the Response XML", e);
}
}
return response;
}
Integration
Next, we will see 2 examples of integration and some aspects to take into account when integrating Powersearch REST Webservice. The first one will search for an address (or partial address) using Global Address operation, and the second one, given a full address, will search for geocode information using Geocode operation.
Global Address Searching
Powersearch REST WebService offers the Global Address operation to find addresses. This operation accepts partial addresses so that the more accurate the address provided is the less addresses will be returned from the service. When the supplied address is accurate enough, the service will return the definitive address which can be formatted by using the format options (format parameter). The code to use Global Address Operation (through the Service Layer previously created) as follows:
private static void doGlobalSearch() throws IOException {
System.out.println("Enter the ISO Country Code: ");
String country = PowersearchOperations.reader.readLine().trim().toUpperCase();
System.out.println("Enter the Address: ");
String address = PowersearchOperations.reader.readLine().trim();
System.out.println("Enter the Format for the returning address: ('NO' to skip) ");
String format = PowersearchOperations.reader.readLine().trim();
if ("NO".equalsIgnoreCase(format)) {
format = null;
}
ClientResponse<GlobalResponse> clientResponse = restService.getGlobalAddress(country, address, sessionKey, format);
GlobalResponse response = clientResponse.getResponse();
if (clientResponse.getStatus() == HttpStatus.SC_OK) {
sessionKey = response.getSessionData().getSessionKey();
if (response.getMatches() != null && response.getMatches().size() > 0) {
System.out.println("Found results:");
for (String retAddress : response.getMatches()) {
System.out.println("\t" + retAddress);
}
}
}
else {
processStatus(clientResponse.getStatus());
if (response.getInformation() != null) {
System.out.println("Message: " + response.getInformation());
}
}
}
As displayed, this is a Console based program. The three parameters to be supplied are Country Code (2 characters ISO Country Code), address or partial address to be found and the format to be applied to the returned address. Note that the format will only be applied in case the Address supplied is accurate enough so that the WebService returns a single address.
Note that the SessionKey returned by the WebService is stored in a sessionKey variable, to be used in the next Global Address request, and then used in the same session. In Powersearch REST Webservice, a Session gathers all the searches needed to find the definitive address with a maximum of 50 searches or 2 minutes.
Geocode Searching
Powersearch REST WebService offers the Geocode operation to get geographical information for an address. The Address supplied to this operation must be accurate enough to be identified unequivocally. Otherwise, the WebService will return a 404 (No Matches found). Thus, a normal process of using Powersearch WebService might be to use Global Address operation (as many times as needed) until a definitive address is found and afterwards supply this address to the Geocode operation in order to get the geographical information. The code to use Geocode Operation (through the Service Layer previously created) is as follows:
private static void doGeocodeSearch() throws IOException {
System.out.println("Enter the ISO Country Code: ");
String country = PowersearchOperations.reader.readLine().trim().toUpperCase();
System.out.println("Enter the Address: ");
String address = PowersearchOperations.reader.readLine().trim();
ClientResponse<GlobalResponse> clientResponse = restService.getGeocode(country, address);
GlobalResponse response = clientResponse.getResponse();
if (clientResponse.getStatus() == HttpStatus.SC_OK) {
System.out.println("Found results:");
System.out.println("\tAddress: " + response.getAddress().getFreeFormat());
System.out.println("\tLatitude: " + response.getAddress().getLatitude());
System.out.println("\tLongitude: " + response.getAddress().getLongitude());
}
else {
processStatus(clientResponse.getStatus());
if (response.getInformation() != null) {
System.out.println("Message: " + response.getInformation());
}
}
}
The two parameters to be supplied are Country Code (2 characters ISO Country Code) and the address that requires a geocode.
Authentication
Powersearch REST WebService uses HTTP Basic Authentication method. This means the client must send the credentials as a header parameter in every request to the Server (in the way the standard says).
In the code supplied, this is done by using the Apache HttpClient library, which hides the way the credentials are sent to the server so that, once the username and password are provided, the rest is done automatically.
Here is the code that uses Apache HttpClient library to provide the credentials:
private HttpResponse getServerResponse(String httpGetQuery,
Map<String, String> params) throws IOException {
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(settings.getIdmUsername(), settings.getIdmPassword());
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();
HttpGet request = new HttpGet(buildHttpGetURL(httpGetQuery, params));
request.addHeader("Accept", settings.getAcceptFormat());
HttpResponse response = client.execute(request);
return response;
}
Http Status Codes Processing
As Powersearch is a REST WebService, the server status information after a request is provided as a HTTP Status code. The codes that could be returned by the service are:
200 - OK
404 - Address or Country not found
400 - Bad Request (something wrong in the request)
401 - Unauthorized (no credentials or bad credentials supplied)
403 - Access Denied (good credentials, but user with incorrect permissions)
500 - Internal Server Error
Thus, it's very useful for the client to process the returned status code in order to know exactly what went wrong with the request. Note that if everything is OK, and some matches for the search are returned (Global Address or Geocode), 200 status code will be returned. Also, if an error code other than 200 is returned by the server, some information will be added to the response, which can be found in the information field.
Below, the code to process the returned HTTP status codes:
private static void processStatus(int status) {
switch(status) {
case HttpStatus.SC_NOT_FOUND:
System.out.println("Response Status Information: " + "Address not found");
break;
case HttpStatus.SC_BAD_REQUEST:
System.out.println("Response Status Information: " + "Invalid Request");
break;
case HttpStatus.SC_FORBIDDEN:
System.out.println("Response Status Information: " + "Access Forbiden");
break;
case HttpStatus.SC_UNAUTHORIZED:
System.out.println("Response Status Information: " + "Wrong User Credentials");
break;
case HttpStatus.SC_INTERNAL_SERVER_ERROR:
System.out.println("Response Status Information: " + "Server Error");
break;
}
}
Configuration Parameters
The sample code supplied uses a configuration file to store some configuration data needed to connect to the Powersearch REST WebService. This data consist of: Service URL, returned data format (JSON or XML), IdM username and IdM password.
The class Settings stores in memory the values of the configuration file and it's used throuhgout the client application. Here is the XML configuration:
<!--?xml version="1.0" encoding="ISO-8859-1"?-->
https://idmp.gb.co.uk/idm-powersearch-rest/powersearch/global
application/json
myuser@mydomain.com
myP@ssW0rD