/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jmcdonnell.blackoutrugby.requests;
import org.jmcdonnell.blackoutrugby.beans.AbstractBlackoutEntity;
import org.jmcdonnell.blackoutrugby.beans.BlackoutApiResponse;
import org.jmcdonnell.blackoutrugby.beans.BlackoutLoginDetails;
import org.jmcdonnell.blackoutrugby.beans.Fixture;
import org.jmcdonnell.blackoutrugby.beans.Member;
import org.jmcdonnell.blackoutrugby.beans.Player;
import org.jmcdonnell.blackoutrugby.beans.Team;
import org.jmcdonnell.blackoutrugby.exceptions.BlackoutException;
import org.jmcdonnell.blackoutrugby.exceptions.BlackoutLoginException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.inject.Named;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.jmcdonnell.blackoutrugby.beans.Lineup;
import org.jmcdonnell.blackoutrugby.beans.MatchEvent;
import org.jmcdonnell.blackoutrugby.beans.MatchScore;
import org.jmcdonnell.blackoutrugby.beans.PlayerHistory;
import org.jmcdonnell.blackoutrugby.beans.PlayerStatistics;
import org.jmcdonnell.blackoutrugby.beans.Standing;
import org.jmcdonnell.blackoutrugby.beans.TeamStatistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author john
*/
@Named
public class RequestManager
{
private final static Logger LOG = LoggerFactory.getLogger(RequestManager.class);
private final static String BLACKOUT_API_BASE_URL = "https://api.blackoutrugby.com/";
private final static String BLACKOUT_API_DEVELOPER_PARAM = "?d=";
private final static String BLACKOUT_API_ENCRYPTED_REQUEST_PARAM = "&er=";
public final static String MEMBER_ACCESS_KEY_PROP = "blackoutrugby.memberaccesskey";
private JAXBContext jaxbContext;
private Unmarshaller unmarshaller;
{
initUnmarshaller();
}
private void initUnmarshaller() {
try {
jaxbContext = JAXBContext.newInstance(new Class[]{
BlackoutApiResponse.class
});
unmarshaller = jaxbContext.createUnmarshaller();
}
catch (JAXBException ex) {
ex.printStackTrace();
LOG.error("Unable to initialise the JAXB Context", ex);
}
}
public BlackoutLoginDetails login(String username, String password) throws BlackoutException {
RequestBuilder builder = RequestBuilder.init();
builder.createLoginRequest(username, password);
BlackoutApiResponse requestEntity = sendLoginRequest(builder.build());
// check if login failed
if (requestEntity.getStatus().equalsIgnoreCase("failed"))
{
throw new BlackoutLoginException(requestEntity.getReason());
}
BlackoutLoginDetails loginDetails = new BlackoutLoginDetails();
loginDetails.setStatus(requestEntity.getStatus());
loginDetails.setKey(requestEntity.getKey());
loginDetails.setMemberId(requestEntity.getMemberId());
loginDetails.setTeamId(requestEntity.getTeamId());
return loginDetails;
}
private BlackoutApiResponse sendApiEntityRequest(String requestString) throws BlackoutException {
BlackoutApiResponse returnedResponse = null;
String encryptedRequestString = encrypt(requestString);
String url = buildUrl(encryptedRequestString);
String response = "";
try {
response = sendHttpGetRequest(url);
}
catch (IOException ioe) {
LOG.error("Error sending HTTP GET request for request: " + requestString, ioe);
}
try {
LOG.info("HTTP GET Response: " + response);
returnedResponse
= (BlackoutApiResponse) unmarshaller.unmarshal(new ByteArrayInputStream(response.getBytes()));
}
catch (JAXBException ex) {
LOG.error("Unable to unmarshall HTTP GET response for request: " + requestString, ex);
}
return returnedResponse;
}
private BlackoutApiResponse sendLoginRequest(String requestString) throws BlackoutException {
BlackoutApiResponse returnedResponse = null;
//TODO: I still need to re-implement the encryption for the login request, otherwise people will be able to "grab"
// login details off users.
//String encryptedRequestString = encrypt(requestString);
String url = buildUrl();
String response = "";
try {
response = sendHttpPost(url+"&dk=" + System.getProperty("dev.key"), requestString);
}
catch (IOException ex) {
LOG.error("Error sending request", ex);
}
try {
LOG.info("URL Response: " + response);
returnedResponse
= (BlackoutApiResponse) unmarshaller.unmarshal(new ByteArrayInputStream(response.getBytes()));
}
catch (JAXBException ex) {
LOG.error("Unable to unmarshall player response", ex);
}
return returnedResponse;
}
private String encrypt(String requestToEncrypt) throws BlackoutException {
LOG.info("Encrypting Request String: " + requestToEncrypt);
KeyGenerator kgen;
try {
LOG.debug("Creating request");
kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
// Create the encryption key and IV from the developer key and IV
SecretKeySpec skeySpec = new SecretKeySpec(
System.getProperty("dev.key").getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(
System.getProperty("dev.iv").getBytes());
// Instantiate the cipher
Cipher cipher;
cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
// Pad the request to a block size of 16 bytes
// (JAVA AES implementation uses 16 byte block sizes)
byte[] requestBytes = requestToEncrypt.getBytes();
Integer blockSize = 16;
Integer requestSize = requestBytes.length;
Integer padding = blockSize - (requestSize % blockSize);
byte[] paddedArray = new byte[requestSize + padding];
System.arraycopy(requestBytes, 0, paddedArray, 0, requestBytes.length);
// Insert padding Zeros
for (int i = (requestBytes.length); i < (paddedArray.length); i++) {
paddedArray[i] = 0;
}
// Encrypt request
byte[] encrypted = cipher.doFinal(paddedArray);
// Encode to base 64
String encodedRequestString = new String(Base64.encodeBase64(encrypted));
LOG.info("Encrypted Request String: " + encodedRequestString);
return encodedRequestString;
}
catch (Exception ex) {
LOG.error("Error while encrypting the request", ex);
throw new BlackoutException("Unable to create encrypted request");
}
}
private String buildUrl() {
StringBuilder stringBuilder = new StringBuilder(BLACKOUT_API_BASE_URL);
stringBuilder.append(BLACKOUT_API_DEVELOPER_PARAM);
stringBuilder.append(System.getProperty("dev.id"));
String accessKey = System.getProperty(MEMBER_ACCESS_KEY_PROP);
if (accessKey != null && !accessKey.isEmpty()) {
stringBuilder.append(accessKey);
}
LOG.info("Request URL is: " + stringBuilder.toString());
return stringBuilder.toString();
}
private String buildUrl(String encryptedRequestString) {
return buildUrl() + BLACKOUT_API_ENCRYPTED_REQUEST_PARAM + encryptedRequestString;
}
private String sendHttpGetRequest(String requestToBePosted) throws IOException {
HttpClient httpclient = new DefaultHttpClient();
LOG.debug("HTTP GET: " + requestToBePosted);
HttpGet httpGet = new HttpGet(requestToBePosted.trim());
// Create a response handler
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String responseBody = httpclient.execute(httpGet, responseHandler);
LOG.debug(responseBody);
return new String(responseBody.getBytes(), Charset.forName("UTF-8"));
}
private String sendHttpPost(String url, String request) throws IOException {
HttpClient httpclient = new DefaultHttpClient();
LOG.debug("HTTP POST: " + url);
HttpPost httpPost = new HttpPost(url.trim());
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
httpPost.setEntity(new StringEntity(request));
// Create a response handler
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String responseBody = httpclient.execute(httpPost, responseHandler);
LOG.debug(responseBody);
return responseBody;
}
public <T extends AbstractBlackoutEntity> T getEntityFromApi(Long entityId, Class<T> entityType,
Boolean isNationalTeam, Boolean isYouthTeam) throws BlackoutException {
RequestBuilder builder = null;
builder = initRequestBuilderByEntityType(entityType, builder);
builder.addId(entityId);
builder.addTeamSettings(isNationalTeam, isYouthTeam);
BlackoutApiResponse sendApiEntityRequest = sendApiEntityRequest(builder.build());
// there should always only be one entity in the list, so we should only
// return the first entity from the list.
return (T) sendApiEntityRequest.getEntities().get(0);
}
public <T extends AbstractBlackoutEntity> List<T> getEntitiesFromApi(
List<Long> entitiesId,
Class<T> entityType, Boolean isNationalTeam, Boolean isYouthTeam) throws BlackoutException {
RequestBuilder builder = null;
builder = initRequestBuilderByEntityType(entityType, builder);
builder.addIds(entitiesId);
builder.addTeamSettings(isNationalTeam, isYouthTeam);
BlackoutApiResponse sendApiEntityRequest = sendApiEntityRequest(builder.build());
return (List<T>) sendApiEntityRequest.getEntities();
}
public <T extends AbstractBlackoutEntity> List<T> getListOfEntityByIdFromApi(
Long entityId, Class<T> entityType, Boolean isNationalTeam, Boolean isYouthTeam) throws BlackoutException {
RequestBuilder builder = null;
builder = initRequestBuilderByEntityType(entityType, builder);
builder.addId(entityId);
builder.addTeamSettings(isNationalTeam, isYouthTeam);
BlackoutApiResponse sendApiEntityRequest = sendApiEntityRequest(builder.build());
return (List<T>) sendApiEntityRequest.getEntities();
}
public List<Player> getPlayersByTeamId(Long teamId, Boolean isNationalTeam, Boolean isYouthTeam) throws BlackoutException {
List<Player> players = new ArrayList<>();
RequestBuilder builder = RequestBuilder.initBuilderForPlayersByTeam();
builder.addId(teamId);
builder.addTeamSettings(isNationalTeam, isYouthTeam);
BlackoutApiResponse sendApiEntityRequest = sendApiEntityRequest(builder.build());
for(AbstractBlackoutEntity player : sendApiEntityRequest.getEntities())
{
players.add((Player)player);
}
return players;
}
private <T extends AbstractBlackoutEntity> RequestBuilder initRequestBuilderByEntityType(Class<T> entityType, RequestBuilder builder) {
if (entityType.equals(Member.class))
{
builder = RequestBuilder.initBuilderForMembers();
}
else if(entityType.equals(Team.class))
{
builder = RequestBuilder.initBuilderForTeams();
}
else if(entityType.equals(Player.class))
{
builder = RequestBuilder.initBuilderForPlayers();
}
else if(entityType.equals(Fixture.class))
{
builder = RequestBuilder.initBuilderForFixtures();
}
else if(entityType.equals(MatchScore.class))
{
builder = RequestBuilder.initBuilderForMatchScore();
}
else if(entityType.equals(PlayerStatistics.class))
{
builder = RequestBuilder.initBuilderForPlayerStatistics();
}
else if(entityType.equals(PlayerHistory.class))
{
builder = RequestBuilder.initBuilderForPlayerHistory();
}
else if(entityType.equals(MatchEvent.class))
{
builder = RequestBuilder.initBuilderForMatchEvent();
}
else if(entityType.equals(Lineup.class))
{
builder = RequestBuilder.initBuilderForLineups();
}
else if(entityType.equals(Standing.class))
{
builder = RequestBuilder.initBuilderForStandings();
}
else if(entityType.equals(TeamStatistics.class))
{
builder = RequestBuilder.initBuilderForTeamStatistics();
}
return builder;
}
public Lineup getLineupForTeamAndFixture(Long teamId, Long fixtureId, Boolean isNationalTeam, Boolean isYouthTeam) throws BlackoutException {
RequestBuilder builder = null;
builder = RequestBuilder.initBuilderForLineups();
builder.addId(teamId);
builder.andAddFixtureId(fixtureId);
builder.addTeamSettings(isNationalTeam, isYouthTeam);
BlackoutApiResponse sendApiEntityRequest = sendApiEntityRequest(builder.build());
return (Lineup) sendApiEntityRequest.getEntities().get(0);
}
public List<Fixture> getLastNumOfFixturesForTeam(Long teamId, Boolean isNational, Boolean isYouth, Integer numberOfFixtures) throws BlackoutException {
RequestBuilder builder = RequestBuilder.initBuildForFixturesForTeam();
builder.addId(teamId);
builder.addTeamSettings(isNational, isYouth);
builder.addLastX(numberOfFixtures);
BlackoutApiResponse request = sendApiEntityRequest(builder.build());
List<Fixture> fixtures = new ArrayList<>(numberOfFixtures);
for (int idx = 0; idx < numberOfFixtures; idx++) {
fixtures.add((Fixture) request.getEntities().get(idx));
}
return fixtures;
}
Fixture getLastFixtureForTeam(Long teamId, Boolean isNational, Boolean isYouth) throws BlackoutException {
return getLastNumOfFixturesForTeam(teamId, isNational, isYouth, 1).get(0);
}
}