/*
* Copyright 2013 Geeoz Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.geeoz.ean.dsl;
import com.geeoz.ean.ws.EanWsException;
import com.ean.wsapi.hotel.v3.BaseRequest;
import com.ean.wsapi.hotel.v3.BaseResponse;
import com.ean.wsapi.hotel.v3.EanWsError;
import com.ean.wsapi.hotel.v3.HotelServices;
import com.ean.wsapi.hotel.v3.LocaleType;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
import java.util.ServiceLoader;
/**
* Base request builder for EAN API requests.
*
* @param <T> type of the builder
* @param <R> type of the request
* @param <S> type of the response
* @author Alex Voloshyn
* @version 1.0 7/13/2013
*/
public abstract class AbstractBuilder<
T extends AbstractBuilder<T, R, S>,
R extends BaseRequest,
S extends BaseResponse> {
/**
* EAN API properties that used by all requests.
*/
protected static final Properties API = new Properties();
/**
* EAN API properties that used for security issues.
*/
private static final Properties API_SECURE = new Properties();
static {
try {
API.load(
Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("ean-api.properties")
);
API_SECURE.load(
Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("ean-api-secure.properties")
);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* EAN-issued access key to the API. Determines your access to live
* bookings, your authentication method (IP or signature-based) and request
* quotas.
*/
private static final String API_KEY = API.getProperty("apiKey");
/**
* EAN-issued account ID. This number is used for tracking sales for
* statistics and commissions purposes on live sites.
*/
private static final long CID = Long.parseLong(API.getProperty("cid"));
/**
* Shared secret for authentication and creating a digital signature.
*/
private static final String SIGN_SECRET =
API_SECURE.getProperty("signatureSecret");
/**
* Used for MD5 generation.
*/
private static final int MILLISECONDS_PER_SECOND = 1000;
/**
* Base request initialisation with digital sign of the request.
*
* @param request base request that should be initialize
*/
protected static void baseInit(final BaseRequest request) {
request.setApiKey(API_KEY);
request.setCid(CID);
if (SIGN_SECRET != null) {
try {
final MessageDigest messageDigest =
MessageDigest.getInstance("MD5");
final long timeInSeconds =
System.currentTimeMillis() / MILLISECONDS_PER_SECOND;
final String input = API_KEY + SIGN_SECRET + timeInSeconds;
messageDigest.update(input.getBytes(Charset.forName("UTF-8")));
final String sig = String.format("%032x",
new BigInteger(1, messageDigest.digest()));
request.setSig(sig);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
/**
* Call built request for response.
*
* @return a response with corresponding type
* @throws EanWsException If your request generates an error, information
* will be contained within this object. See our
* exceptions overview for details on this object.
*/
public final S call() throws EanWsException {
S response = response();
final EanWsError error = response.getEanWsError();
if (error == null) {
return response;
} else {
throw new EanWsException(error);
}
}
/**
* Add currency code parameter to EAN API request.
*
* @param code a currency code for request
* @return builder instance
*/
public final T currency(final String code) {
request().setCurrencyCode(code);
return self();
}
/**
* Add customer parameters to EAN API request.
*
* @param sessionId customer session ID
* @param ipAddress customer IP address
* @param userAgent customer user agent
* @return builder instance
*/
public final T customer(final String sessionId,
final String ipAddress,
final String userAgent) {
request().setCustomerSessionId(sessionId);
request().setCustomerIpAddress(ipAddress);
request().setCustomerUserAgent(userAgent);
return self();
}
/**
* Add locale parameter to EAN API request.
*
* @param locale a locale for request
* @return builder instance
*/
public final T locale(final LocaleType locale) {
request().setLocale(locale);
return self();
}
/**
* Creates hotel services instance.
*
* @return a new service that was found first or <code>null</code> - if not
*/
protected final HotelServices getHotelServices() {
final ServiceLoader<HotelServices> services =
ServiceLoader.load(HotelServices.class);
if (services.iterator().hasNext()) {
return services.iterator().next();
}
return null;
}
/**
* Retrieve an instance of the base request that should be modified.
*
* @return an instance of base request
*/
protected abstract R request();
/**
* Retrieve response from EAN services.
*
* @return a response
*/
protected abstract S response();
/**
* Retrieve an instance of the current class casted to highest type in
* hierarchy.
* <p/>
* Used for returning base builder method results casted to used class. As a
* simplest implementation should return <code>this</code> variable;
*
* @return casted instance
*/
protected abstract T self();
}