public interface PropertyKey {

  // The URLs
  String USER_PROFILE_URL = "USER_PROFILE_URL";
  String USER_GAME_LIST_URL = "USER_GAME_LIST_URL";
  String USER_GAME_ACHIEVE_URL = "USER_GAME_ACHIEVE_URL";
  
  
  
  // User Profile XPath
  String USER_PROFILE_GAME_TAG = "USER_PROFILE_GAME_TAG";
  String USER_PROFILE_GAME_PIC = "USER_PROFILE_GAME_PIC";
  String USER_PROFILE_RECENT_ACTIVE = "USER_PROFILE_RECENT_ACTIVE";
  String USER_PROFILE_GAME_SCORE = "USER_PROFILE_GAME_SCORE";
  String USER_PROFILE_REPUTATION_LEVEL = "USER_PROFILE_REPUTATION_LEVEL";
  String USER_PROFILE_LOCATION = "USER_PROFILE_LOCATION";
  String USER_PROFILE_BIO = "USER_PROFILE_BIO";
  
  
  // User Game List XPath
  String GAME_ACHIEVE_EARNED = "GAME_ACHIEVE_EARNED";
  String GAME_COMPLETION = "GAME_COMPLETION";
  String GAME_POINT_COMPLETION = "GAME_POINT_COMPLETION";
  String GAME_IMAGE = "GAME_IMAGE";
  String GAME_TITLE = "GAME_TITLE";
  String GAME_COLLECTION_LIST = "GAME_COLLECTION_LIST";
  String GAME_URL = "GAME_URL";

  
  // User Game Achievement XPath
  String ACHIEVE_GAME_TITLE = "ACHIEVE_GAME_TITLE";
  String ACHIEVE_POINT = "ACHIEVE_POINT";
  String ACHIEVE_COLLECTION_ITEM = "ACHIEVE_COLLECTION_ITEM";
  String ACHIEVE_DESCRIPTION = "ACHIEVE_DESCRIPTION";
  String ACHIEVE_UNLOCKED_DATE = "ACHIEVE_UNLOCKED_DATE";
  String ACHIEVE_IMAGE = "ACHIEVE_IMAGE";
  String ACHIEVE_TITLE1 = "ACHIEVE_TITLE1";
  String ACHIEVE_TITLE2 = "ACHIEVE_TITLE2";
  String ACHIEVE_DATE_FORMAT = "ACHIEVE_DATE_FORMAT";
} public class XblAchievement {

  private String gameId;
  private String achievementId;
  private String title;
  private String description;
  private short point;
  private String imageUrl;
  /**
   * @return the gameId
   */
  public String getGameId() {
    return gameId;
  }
  /**
   * @param gameId the gameId to set
   */
  public void setGameId(String gameId) {
    this.gameId = gameId;
  }
  /**
   * @return the achievementId
   */
  public String getAchievementId() {
    return achievementId;
  }
  /**
   * @param achievementId the achievementId to set
   */
  public void setAchievementId(String achievementId) {
    this.achievementId = achievementId;
  }
  /**
   * @return the title
   */
  public String getTitle() {
    return title;
  }
  /**
   * @param title the title to set
   */
  public void setTitle(String title) {
    this.title = title;
  }
  /**
   * @return the description
   */
  public String getDescription() {
    return description;
  }
  /**
   * @param description the description to set
   */
  public void setDescription(String description) {
    this.description = description;
  }
  /**
   * @return the point
   */
  public short getPoint() {
    return point;
  }
  /**
   * @param point the point to set
   */
  public void setPoint(short point) {
    this.point = point;
  }
  /**
   * @return the imageUrl
   */
  public String getImageUrl() {
    return imageUrl;
  }
  /**
   * @param imageUrl the imageUrl to set
   */
  public void setImageUrl(String imageUrl) {
    this.imageUrl = imageUrl;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    return ObjectUtil.buildToStringByReflect(this);
  }
} public class XblGame {

  private String gameId;
  private String title;
  private short totalPoint;
  private byte AchievementCount;
  private String imageUrl;
  private List<Platform> platform;
  /**
   * @return the gameId
   */
  public String getGameId() {
    return gameId;
  }
  /**
   * @param gameId the gameId to set
   */
  public void setGameId(String gameId) {
    this.gameId = gameId;
  }
  /**
   * @return the title
   */
  public String getTitle() {
    return title;
  }
  /**
   * @param title the title to set
   */
  public void setTitle(String title) {
    this.title = title;
  }
  /**
   * @return the totalPoint
   */
  public short getTotalPoint() {
    return totalPoint;
  }
  /**
   * @param totalPoint the totalPoint to set
   */
  public void setTotalPoint(short totalPoint) {
    this.totalPoint = totalPoint;
  }
  /**
   * @return the achievementCount
   */
  public byte getAchievementCount() {
    return AchievementCount;
  }
  /**
   * @param achievementCount the achievementCount to set
   */
  public void setAchievementCount(byte achievementCount) {
    AchievementCount = achievementCount;
  }
  /**
   * @return the imageUrl
   */
  public String getImageUrl() {
    return imageUrl;
  }
  /**
   * @param imageUrl the imageUrl to set
   */
  public void setImageUrl(String imageUrl) {
    this.imageUrl = imageUrl;
  }
  /**
   * @return the platform
   */
  public List<Platform> getPlatform() {
    return platform;
  }
  /**
   * @param platform the platform to set
   */
  public void setPlatform(List<Platform> platform) {
    this.platform = platform;
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    return ObjectUtil.buildToStringByReflect(this);
  }
} public class XblUserAchievement extends XblAchievement {

  private boolean earned;
  private Date earnedDate;
  /**
   * @return the earned
   */
  public boolean isEarned() {
    return earned;
  }
  /**
   * @param earned the earned to set
   */
  public void setEarned(boolean earned) {
    this.earned = earned;
  }
  /**
   * @return the earnedDate
   */
  public Date getEarnedDate() {
    return earnedDate;
  }
  /**
   * @param earnedDate the earnedDate to set
   */
  public void setEarnedDate(Date earnedDate) {
    this.earnedDate = earnedDate;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    return ObjectUtil.buildToStringByReflect(this);
  }
} public class XblUserGame extends XblGame {

  private short earnedPoint;
  private byte earnedAchievementCount;
  private byte completion;
  /**
   * @return the earnedPoint
   */
  public short getEarnedPoint() {
    return earnedPoint;
  }
  /**
   * @param earnedPoint the earnedPoint to set
   */
  public void setEarnedPoint(short earnedPoint) {
    this.earnedPoint = earnedPoint;
  }
  /**
   * @return the earnedAchievement
   */
  public byte getEarnedAchievementCount() {
    return earnedAchievementCount;
  }
  /**
   * @param earnedAchievement the earnedAchievement to set
   */
  public void setEarnedAchievementCount(byte earnedAchievement) {
    this.earnedAchievementCount = earnedAchievement;
  }
  /**
   * @return the completion
   */
  public byte getCompletionByPercent() {
    return completion;
  }
  /**
   * @param completion the completion to set
   */
  public void setCompletionByPercent(byte completion) {
    this.completion = completion;
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    return ObjectUtil.buildToStringByReflect(this);
  }
} public class XblUserProfile {
  /** the user id. **/
  private String userId;
  /** the user name. **/
  private String username;
  /** the user's avatar url. **/
  private String userAvatarUrl;
  /** the user total earned points. **/
  private long totalPoint;
  /** the user's reputation. **/
  private String reputation;
  /** the user's location. **/
  private String location;
  /** the user's bio . **/
  private String bio;
  /** the user's recent active. **/
  private String recentActive;
  
  /**
   * @return the userId
   */
  public String getUserId() {
    return userId;
  }
  /**
   * @param userId the userId to set
   */
  public void setUserId(String userId) {
    this.userId = userId;
  }
  /**
   * @return the username
   */
  public String getUsername() {
    return username;
  }
  /**
   * @param username the username to set
   */
  public void setUsername(String username) {
    this.username = username;
  }
  /**
   * @return the userAvatarUrl
   */
  public String getUserAvatarUrl() {
    return userAvatarUrl;
  }
  /**
   * @param userAvatarUrl the userAvatarUrl to set
   */
  public void setUserAvatarUrl(String userAvatarUrl) {
    this.userAvatarUrl = userAvatarUrl;
  }
  /**
   * @return the totalPoint
   */
  public long getTotalPoint() {
    return totalPoint;
  }
  /**
   * @param totalPoint the totalPoint to set
   */
  public void setTotalPoint(long totalPoint) {
    this.totalPoint = totalPoint;
  }
  /**
   * @return the reputation
   */
  public String getReputation() {
    return reputation;
  }
  /**
   * @param reputation the reputation to set
   */
  public void setReputation(String reputation) {
    this.reputation = reputation;
  }
  /**
   * @return the location
   */
  public String getLocation() {
    return location;
  }
  /**
   * @param location the location to set
   */
  public void setLocation(String location) {
    this.location = location;
  }
  /**
   * @return the bio
   */
  public String getBio() {
    return bio;
  }
  /**
   * @param bio the bio to set
   */
  public void setBio(String bio) {
    this.bio = bio;
  }
  /**
   * @return the recentActive
   */
  public String getRecentActive() {
    return recentActive;
  }
  /**
   * @param recentActive the recentActive to set
   */
  public void setRecentActive(String recentActive) {
    this.recentActive = recentActive;
  }
  
  /**
   * @see java.lang.Object#toString()
   */
  @Override
  public String toString() {
    return ObjectUtil.buildToStringByReflect(this);
  }
} public class ServiceException extends Exception {

  /**
   * 
   */
  private static final long serialVersionUID = 1L;

  public ServiceException() {
    super();
  }

  public ServiceException(String message, Throwable cause) {
    super(message, cause);
  }

  public ServiceException(String message) {
    super(message);
  }

  public ServiceException(Throwable cause) {
    super(cause);
  }
} public class XblUserGameAchieveParser extends HttpContentParser<List<XblUserAchievement>> {
  
  /** the configuration. */
  private static final Configuration configuration = Configuration.INSTANCE;

  /**
   * {@inheritDoc}
   */
  @Override
  protected List<XblUserAchievement> parseDoc(Document doc) throws ParseException {
    List<XblUserAchievement> achieveList = null;
    try {
      String gameTitle = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.ACHIEVE_GAME_TITLE), doc);
      // the collection list
      NodeList achievements = XMLUtil.xpathEvaluateNodeList(
          configuration.getStringProperty(PropertyKey.ACHIEVE_COLLECTION_ITEM), doc);
      if (null != achievements) {
        achieveList = new ArrayList<>();
        int length = achievements.getLength();
        // length == achievement.count
        if (logger.isDebugEnabled()) {
          logger.debug(gameTitle + "'s achievement count=" + length);
        }
        for (int i = 0; i < length; i++) {
          Node achieveNode = achievements.item(i);
          // achievement will with detail link.
          String achieveTitle = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.ACHIEVE_TITLE1), achieveNode);
          if (StringUtil.isBlank(achieveTitle)) {
            achieveTitle = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.ACHIEVE_TITLE2), achieveNode);
          }
          String achieveDescription = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.ACHIEVE_DESCRIPTION), achieveNode);
          
          String achievePoint = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.ACHIEVE_POINT), achieveNode);
          String achieveUnlockDate = null;
          String achieveImage = null;
          boolean unlocked = null != achievePoint;
          if (unlocked) {
            // unlocked achieve
            achieveUnlockDate = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.ACHIEVE_UNLOCKED_DATE), achieveNode);
            achieveImage = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.ACHIEVE_IMAGE), achieveNode);
          }
          
          if (logger.isDebugEnabled()) {
            logger.debug("Achievement for Game:" + gameTitle);
            logger.debug("achieveTitle=" + achieveTitle);
            logger.debug("achieveDescription=" + achieveDescription);
            logger.debug("achieveUnlocked=" + unlocked);
            logger.debug("achievePoint=" + achievePoint);
            logger.debug("achieveUnlockDate=" + achieveUnlockDate);
            logger.debug("achieveImage=" + achieveImage);
          }
          
          XblUserAchievement achieve = new XblUserAchievement();
          achieve.setDescription(tidyUpSpanText(achieveDescription));
          achieve.setTitle(tidyUpSpanText(achieveTitle));
          achieve.setEarned(unlocked);
          
          if (unlocked) {
            Integer point = parseString2Integer(tidyUpSpanText(achievePoint), "Failed to parse the achievement point. ");
            achieve.setPoint(point.shortValue());
            achieve.setImageUrl(achieveImage);
            Date earnedDate = null;
            String tidyedDate = tidyUpSpanText(achieveUnlockDate);
            try {
              earnedDate = DateUtil.parserDateStr(tidyedDate, configuration.getStringProperty(PropertyKey.ACHIEVE_DATE_FORMAT));
            } catch (java.text.ParseException pe) {
              // parse failed. 
              // first parse the string to date. eg: Unlocked 3 minutes ago, Unlocked 3 hours ago, Unlocked 1 day ago ...
              earnedDate = parseRecentlyDate(tidyedDate);
              if (null == earnedDate) {
                // failed to parse recently date, logging error
                logger.warn("fild to parse unlocked date. Caused by: " + pe);
              }
            }
            achieve.setEarnedDate(earnedDate);
          }
          
          achieveList.add(achieve);
        }
      }
    } catch (Exception e) {
      throw new ParseException(e);
    }
    return achieveList;
  }

  // Unlocked 3 minutes ago, Unlocked 3 hours ago, Unlocked 1 day ago ...
  private Date parseRecentlyDate(final String achieveUnlockDate) {
    Date date = null;
    String recentlyStr = achieveUnlockDate;
    recentlyStr = recentlyStr.replace("Unlocked ", "").replace(" ago", "");
    String[] split = recentlyStr.split(StringConstants.SPACE);
    if (2 == split.length) {
      String number = split[0];
      String unit = split[1];
      
      Integer n = Integer.parseInt(number);
      date = DateUtil.getCurrentDate();
      if (unit.startsWith("minute")) {
        date = DateUtil.addMinute(date, -1 * n);
      } else if (unit.startsWith("hour")) {
        date = DateUtil.addHour(date, -1 * n);
      } else if (unit.startsWith("day")) {
        date = DateUtil.addDay(date, -1 * n);
      }
    }
    return date;
  }
} public class XblUserGameListParser extends HttpContentParser<List<XblUserGame>> {
  
  /** the configuration. */
  private static final Configuration configuration = Configuration.INSTANCE;

  /**
   * {@inheritDoc}
   */
  @Override
  protected List<XblUserGame> parseDoc(Document doc) throws ParseException {
    List<XblUserGame> gameCollections = null;
    try {
      // the collection list
      NodeList collectionList = XMLUtil.xpathEvaluateNodeList(
          configuration.getStringProperty(PropertyKey.GAME_COLLECTION_LIST), doc);
      if (null != collectionList) {
        gameCollections = new ArrayList<XblUserGame>();
        int length = collectionList.getLength();
        if (logger.isDebugEnabled()) {
          logger.debug("game collection count: " + length);
        }
        for (int i = 0; i < length; i++) {
          if (logger.isDebugEnabled()) {
            logger.debug("loading game collection: " + i);
          }
          XblUserGame game = new XblUserGame();
          Node collection = collectionList.item(i);
          String gameTitle = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.GAME_TITLE),
              collection);
          String gameUrl = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.GAME_URL),
              collection);
          String gameImage = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.GAME_IMAGE),
              collection);
          String completionPercentage = XMLUtil.xpathEvaluateString(
              configuration.getStringProperty(PropertyKey.GAME_COMPLETION), collection);
          String pointCompletion = XMLUtil.xpathEvaluateString(
              configuration.getStringProperty(PropertyKey.GAME_POINT_COMPLETION), collection);
          String achieveEarned = XMLUtil.xpathEvaluateString(
              configuration.getStringProperty(PropertyKey.GAME_ACHIEVE_EARNED), collection);
          if (logger.isDebugEnabled()) {
            logger.debug("gameTitle=" + gameTitle);
            logger.debug("gameUrl=" + gameUrl);
            logger.debug("gameImage=" + gameImage);
            logger.debug("completionPercentage=" + completionPercentage);
            logger.debug("pointCompletion=" + pointCompletion);
            logger.debug("achieveEarned=" + achieveEarned);
          }
          // completion
          Integer completion = parseString2Integer(completionPercentage, "Parsing completion failed. ");
          game.setCompletionByPercent(completion.byteValue());

          // earned achievement count
          Integer earnedAchievement = parseString2Integer(tidyUpSpanText(achieveEarned), "Parsing earned achievement failed. ");
          game.setEarnedAchievementCount(earnedAchievement.byteValue());
          
          // only set the achievement count when 100% completion.
          if (100 == completion) {
            game.setAchievementCount(earnedAchievement.byteValue());
          }

          // earned points and total points
          if (null != pointCompletion) {
            String[] split = tidyUpSpanText(pointCompletion).split(StringConstants.SLASH);
            if (2 == split.length) {
              String ep = split[0];
              String tp = split[1];
              Integer earnedPoint = parseString2Integer(ep, "Parsing earned point failed. ");
              game.setEarnedPoint(earnedPoint.shortValue());
              Integer totalPoint = parseString2Integer(tp, "Parsing total point failed. ");
              game.setTotalPoint(totalPoint.shortValue());
            }
          }
          // title
          game.setTitle(gameTitle);
          // image url
          game.setImageUrl(gameUrl);
          // game id
          String gameId = getGameIdFromUrl(gameUrl);
          game.setGameId(gameId);
          // platform
          List<Platform> pl = new ArrayList<Platform>();
          pl.add(Platform.getPlatformFromString(gameId.substring(0, gameId.lastIndexOf(StringConstants.SLASH))));
          game.setPlatform(pl);

          gameCollections.add(game);
        }
      }

    } catch (Exception e) {
      throw new ParseException(e);
    }

    return gameCollections;
  }

  /**
   * Get the game id from game url.
   * @param gameUrl the game url
   * @return the game id
   */
  private String getGameIdFromUrl(String gameUrl) {
    int secLastSlashIdx = gameUrl.substring(0, gameUrl.lastIndexOf(StringConstants.SLASH)).lastIndexOf(
        StringConstants.SLASH);
    String s = gameUrl.substring(secLastSlashIdx + 1, gameUrl.lastIndexOf(StringConstants.QUESTION));
    return s;
  }
} public class XblUserProfileParser extends HttpContentParser<XblUserProfile> {
  
  /** the configuration. */
  private static final Configuration configuration = Configuration.INSTANCE;
  
  /**
   * {@inheritDoc}
   */
  @Override
  public XblUserProfile parseDoc(Document doc) throws ParseException {
    XblUserProfile profile = null;
    try {
      profile = new XblUserProfile();
      profile.setBio(XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.USER_PROFILE_BIO), doc));
      profile.setLocation(XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.USER_PROFILE_LOCATION), doc));
      profile.setRecentActive(XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.USER_PROFILE_RECENT_ACTIVE), doc));
      String totalPoint = XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.USER_PROFILE_GAME_SCORE), doc);
      long points = 0;
      Number number = NumberFormat.getInstance(Locale.US).parse(totalPoint);
      points = number.longValue();
      profile.setTotalPoint(points);
      profile.setReputation(XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.USER_PROFILE_REPUTATION_LEVEL), doc));
      profile.setUserAvatarUrl(XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.USER_PROFILE_GAME_PIC), doc));
      profile.setUsername(XMLUtil.xpathEvaluateString(configuration.getStringProperty(PropertyKey.USER_PROFILE_GAME_TAG), doc));
      
    } catch (Exception e) {
      // TODO
      throw new ParseException(e);
    }
    return profile;
  }

} public class BaseRetriever extends CookieInjectRetriever {

  /** the logger. */
  private static final Log logger = LogFactory.getLog(BaseRetriever.class);

  /** the system setting. */
  private static SystemSetting systemSetting = SystemSetting.INSTANCE;
  
  /** the cookie file. */
  private static final String COOKIE_FILE = "cookie/" + systemSetting.getMSLiveUsername() + FileExtensionConstants.TEXT_EXTENSION;

  /**
   * Constructor.
   * 
   * @param url
   *          the url
   * @param parser
   *          the parser
   */
  public BaseRetriever(String url) {
    super(url, Method.GET_METHOD);
  }

  /**
   * Check the cookie valid or not.
   * 
   * @return check wether the cookie is valid or not.
   */
  private boolean checkCookieValid() {
    File cookieFile = new File(COOKIE_FILE);
    if (cookieFile.exists()) {
      // TODO need to be checked
      long lastApiCalledTime = systemSetting.getLastApiCalledTime();
      if (System.currentTimeMillis() - lastApiCalledTime > DateUtil.DAY) {
        // expired
        return false;
      }
      return true;
    }
    
    return false;
  }

  /**
   * Login into the MS Live.
   * 
   * @throws IOException
   *           on error
   * @throws URISyntaxException
   *           on error
   * @throws LoginFailedException
   *           when login failed
   */
  private void loginIntoLive() throws IOException, URISyntaxException, LoginFailedException {
    String loginScript = StringConstants.EMPTY_STRING;
    Path path = Paths.get(this.getClass().getClassLoader().getResource("loginLive.js").toURI());
    if (null != path) {
      loginScript = path.toString();
    }
    if (StringUtil.isEmpty(loginScript)) {
      throw new NullPointerException("loginScript is empty.");
    }
    ProcessExecutor pe = new ProcessExecutor("casperjs", loginScript, systemSetting.getMSLiveUsername(),
        systemSetting.getMSLivePassword());
    pe.execute();

    // dump the output
    StringBuilder sb = new StringBuilder();
    String standardOutput = pe.writeStandardOutputToString();
    sb.append("Standard Output:").append(standardOutput).append(StringUtil.newline());
    
    String errorMsg = pe.writeErrorOutputToString();
    sb.append("Error Output:").append(errorMsg);
    
    if (logger.isDebugEnabled()) {
      logger.debug(sb.toString());
    }
    
    int exitValue = pe.getExitValue();
    if (logger.isDebugEnabled()) {
      logger.debug("login process returns " + exitValue);
    }
    if (0 != pe.getExitValue()) {
      throw new LoginFailedException("login failed. please check your MS live username and password. login dump: " + sb.toString());
    }

  }

  /**
   * Read the cookies from saved cookie file.
   * 
   * @return the cookies
   * @throws IOException
   *           on error
   */
  protected Cookie[] readCookies() throws Exception {
    if (!checkCookieValid()) {
      try {
        loginIntoLive();
      } catch (URISyntaxException | LoginFailedException e) {
        throw e;
      }
    }
    systemSetting.updateLastApiCalledTime();
    
    Cookie[] co = null;
    File cookieFile = new File(COOKIE_FILE);
    if (cookieFile.exists()) {
      String cookieInfo = FileUtil.readFile2String(cookieFile.getAbsolutePath());
      if (null != cookieInfo) {
        String[] cookies = cookieInfo.split(StringConstants.AND);
        co = new Cookie[cookies.length];
        int i = 0;
        for (String cookie : cookies) {
          String[] split = cookie.split(StringConstants.EQUAL);
          String cookieKey = split[0];
          String cookieValue = split[1];
          if (logger.isDebugEnabled()) {
            logger.debug("cookie: " + cookieKey + "=" + cookieValue);
          }
          // update the expiration to 1 day.
          co[i++] = createCookie(".xbox.com", cookieKey, cookieValue, StringConstants.SLASH, DateUtil.DAY);
        }
      }
    } else {
      throw new IllegalStateException("Cookie file doesn't exist");
    }
    return co;
  }

  @Override
  protected void configHttpMethod(HttpClient client, HttpMethod httpMethod) throws RetrieveException {
  }

} public class Configuration extends CommonConfiguration {
  /** the XBox live URL properties. */
  private static final String XBL_URL_PROPERTIES = "XblUrls.properties";
  /** the user profile xpath properties. */
  private static final String USER_PROFILE_XPATH_PROPERTIES = "UserProfileXPath.properties";
  /** the user's game list xpath properties. */
  private static final String USER_GAME_LIST_XPATH_PROPERTIES = "GameListXPath.properties";
  /** the user's game achievement list xpath properties. */
  private static final String USER_GAME_ACHIEVE_XPATH_PROPERTIES = "GameAchieveXPath.properties";
  /** the properties file list. */
  private static final List<String> propertiesList = new ArrayList<String>();
  
  /**
   * initialize the properties list.
   */
  static {
    propertiesList.add(XBL_URL_PROPERTIES);
    propertiesList.add(USER_PROFILE_XPATH_PROPERTIES);
    propertiesList.add(USER_GAME_LIST_XPATH_PROPERTIES);
    propertiesList.add(USER_GAME_ACHIEVE_XPATH_PROPERTIES);
  }
  
  /** the singleton instance. */
  public static final Configuration INSTANCE = new Configuration();
  
  /**
   * Constructor.
   */
  private Configuration() {
    super();
  }

  /**
   * Load the resource files.
   */
  protected void loadResources() {
    try {
      for (String p : propertiesList) {
        properties.load(Configuration.class.getClassLoader().getResourceAsStream(p));
      }
    } catch (IOException e) {
      throw new IllegalStateException("Cannot initialize the configuration: " + e);
    }
  }
}
import java.text.MessageFormat;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.elminster.common.util.ExceptionUtil;
import com.elminster.retrieve.xbox.constants.PropertyKey;
import com.elminster.retrieve.xbox.data.game.XblAchievement;
import com.elminster.retrieve.xbox.data.game.XblGame;
import com.elminster.retrieve.xbox.data.user.XblUserAchievement;
import com.elminster.retrieve.xbox.data.user.XblUserGame;
import com.elminster.retrieve.xbox.data.user.XblUserProfile;
import com.elminster.retrieve.xbox.exception.ServiceException;
import com.elminster.retrieve.xbox.parser.XblUserGameAchieveParser;
import com.elminster.retrieve.xbox.parser.XblUserGameListParser;
import com.elminster.retrieve.xbox.parser.XblUserProfileParser;
import com.elminster.retrieve.xbox.runnable.BaseRetriever;
import com.elminster.retrieve.xbox.util.Configuration;
package com.elminster.retrieve.xbox.service;




/**
 * The Xbox API implementation.
 * 
 * @author jgu
 * @version 1.0
 */
public class XboxApiImpl implements IXboxApi {
  
  /** the logger. */
  private static final Log logger = LogFactory.getLog(XboxApiImpl.class);

  /**
   * {@inheritDoc}
   */
  @Override
  public XblUserProfile getXblUserProfile(String xblUsername) throws ServiceException {