Package com.jbidwatcher.auction.server

Source Code of com.jbidwatcher.auction.server.AuctionServer

package com.jbidwatcher.auction.server;
/*
* Copyright (c) 2000-2007, CyberFOX Software, Inc. All Rights Reserved.
*
* Developed by mrs (Morgan Schweers)
*/

/*
* @file   AuctionServer.java
* @author Morgan Schweers <cyberfox@jbidwatcher.com>
* @date   Wed Oct  9 13:49:02 2002
* @note   Library GPL'ed.
* @brief  This is an interface description for the general auction Servers
*
* It allows abstracting the auction setup to a factory creator, so
* the factory can identify which site (ebay, yahoo, amazon, etc.) it
* is, and do the appropriate parsing for that site.
*/
import com.jbidwatcher.util.config.*;
import com.jbidwatcher.util.queue.MQFactory;
import com.jbidwatcher.util.queue.AuctionQObject;
import com.jbidwatcher.util.http.CookieJar;
import com.jbidwatcher.util.http.Http;
import com.jbidwatcher.util.Constants;
import com.jbidwatcher.util.StringTools;
import com.jbidwatcher.search.SearchManagerInterface;
import com.jbidwatcher.auction.*;

import java.util.*;
import java.net.*;
import java.io.*;

public abstract class AuctionServer implements AuctionServerInterface {
  private static long sLastUpdated = 0;

  public String stripId(String source) {
    String strippedId = source;

    if (source.startsWith("http")) {
      strippedId = extractIdentifierFromURLString(source);
    }

    return strippedId;
  }

  private static class ReloadItemException extends Exception { }

  //  Note: JBidProxy
  public abstract CookieJar getNecessaryCookie(boolean force);

  //  UI functions
  //  Note: AuctionServerManager
  public abstract ServerMenu establishMenu();

  //  Note: AuctionServerManager
  public abstract void cancelSearches();
  public abstract void addSearches(SearchManagerInterface searchManager);

    //  Exposed to AuctionEntry for checking high bidder status.
  public abstract void updateHighBid(String ae);

  public abstract void setSnipe(String auctionId);
  public abstract void cancelSnipe(String identifier);


  /**
   * @brief Get the string-form URL for a given item ID on this
   * auction server, for when we aren't browsing.
   *
   * Note: AuctionEntry, JBWDropHandler
   *
   * @param itemID - The item to retrieve the URL for.
   *
   * @return - A String with the full URL of the item description on the auction server.
   */
  public abstract String getStringURLFromItem(String itemID);

  /**
   * @brief Allocate a new auction that is of this auction server's specific subtype.
   *
   * In order for the auctions to be able to fill out relevant
   * information, each has to have a subclass of AuctionInfo dedicated
   * to it.  This abstract function is defined by the auction server
   * specific classes, and actually returns an object of their type of
   * 'auction'.
   *
   *  Note: AuctionEntry
   *
   * @return - A freshly allocated auction-server specific auction data object.
   */
  public abstract SpecificAuction getNewSpecificAuction();

  /**
   * @brief Get the official 'right now' time from the server.
   *
   * @return - The current time as reported by the auction site's 'official time' mechanism.
   */
  protected abstract Date getOfficialTime();

  /**
   * @brief Given a site-dependant item ID, get the URL for that item.
   *
   * @param itemID - The eBay item ID to get a net.URL for.
   *
   * @return - a URL to use to pull that item.
   */
  protected URL getURLFromItem(String itemID) {
    return StringTools.getURLFromString(getStringURLFromItem(itemID));
  }

  /**
   * Get the full text of an auction from the auction server.
   *
   * @param id - The item id for the item to retrieve from the server.
   *
   * @return - The full text of the auction from the server, or null if it wasn't found.
   * @throws java.io.FileNotFoundException - If the auction is gone from the server.
   */
  protected abstract StringBuffer getAuction(String id) throws FileNotFoundException;

  /**
   * @brief Get the current time inline with the current thread.  This will
   * block until it's done getting the time.
   */
  public void reloadTime() {
    if (getOfficialTime() != null) {
      MQFactory.getConcrete("Swing").enqueue("Successfully synchronized time with " + getFriendlyName() + '.');
      JConfig.log().logMessage("Time delta with " + getFriendlyName() + " is " + getServerTimeDelta());
    } else {
      MQFactory.getConcrete("Swing").enqueue("Failed to synchronize time with " + getFriendlyName() + '!');
    }
  }

  //  Generalized logic
  //  -----------------
  //  Note: AuctionEntry
  public AuctionInfo create(String itemId) {
    return loadAuction(itemId, null);
  }

  /**
   * @brief Load an auction from a given URL, and return the textual
   * form of that auction to the caller in a Stringbuffer, having
   * passed in any necessary cookies, passwords, etc.
   *
   * @param auctionURL - The URL of the auction to load.
   *
   * @return - A StringBuffer containing the text of the auction at that URL.
   *
   * @throws java.io.FileNotFoundException -- If the URL doesn't exist on the auction server.
   */
  public StringBuffer getAuction(URL auctionURL) throws FileNotFoundException {
    if(auctionURL == null) return null;
    StringBuffer loadedPage;

    try {
      CookieJar curCook = getNecessaryCookie(false);
      URLConnection uc;
      if(curCook != null) {
        uc = curCook.connect(auctionURL.toString());
      } else {
        uc = Http.net().makeRequest(auctionURL, null);
      }
      loadedPage = Http.net().receivePage(uc);
      if(loadedPage != null && loadedPage.length() == 0) {
        loadedPage = null;
      }
    } catch(FileNotFoundException fnfe) {
      JConfig.log().logDebug("Item not found: " + auctionURL.toString());
      throw fnfe;
    } catch(IOException e) {
      JConfig.log().handleException("Error loading URL (" + auctionURL.toString() + ')', e);
      loadedPage = null;
    }
    return loadedPage;
  }

  /**
   * @brief Given an auction entry, reload/update the core auction information from the server.
   *
   * Note: AuctionEntry
   *
   * @param auctionId
   * @return - The core auction information that has been set into the
   * auction entry, or null if the update failed.
   */
  public void reload(String auctionId) {
    AuctionEntry ae = (AuctionEntry) EntryCorral.getInstance().takeForWrite(auctionId);
    SpecificAuction curAuction;
    try {
      curAuction = (SpecificAuction) loadAuction(auctionId, ae);

      if (curAuction != null) {
        curAuction.saveDB();
        ae.setAuctionInfo(curAuction);
        ae.clearInvalid();
        MQFactory.getConcrete("Swing").enqueue("LINK UP");
      } else {
        if(!ae.isDeleted() && !ae.getLastStatus().contains("Seller away - item unavailable.")) {
          ae.setLastStatus("Failed to load from server!");
          ae.setInvalid();
        }
      }
    } finally {
      EntryCorral.getInstance().release(auctionId);
    }
  }

  /**
   * @brief Load an auction, given its item id, and its 'AuctionEntry'.
   *
   * @param item_id - The item # to associate this returned info with.
   * @param ae - An object to notify when an error occurs.
   *
   * @return - An object containing the information extracted from the auction.
   */
  private AuctionInfo loadAuction(String item_id, AuctionEntry ae) {
    StringBuffer sb = null;
    SpecificAuction curAuction = null;
    int runCount = 0;

    // Retry loop
    while(sb == null && runCount < 2) {
      sb = retrieveAuction(item_id, ae);

      // If there was a failure retrieving the HTML itself, we probably got a 404.
      if(sb == null && (ae == null || ae.isDeleted())) {
        if(ae != null) ae.saveDB();
        return null;
      }

      try {
        curAuction = doParse(sb, ae, item_id);
      } catch (ReloadItemException e) {
        sb = null;
      }
      runCount++;
    }

    if (curAuction == null) {
      JConfig.log().logMessage("Multiple failures attempting to load item " + item_id + ", giving up.");

      if (ae != null && ae.getLastStatus().contains("Seller away - item unavailable.")) {
        ae.setInvalid();
      } else if (ae == null || !ae.isDeleted()) {
        noteRetrieveError(ae);
      }
    }
    return curAuction;
  }

  private StringBuffer retrieveAuction(String item_id, AuctionEntry ae) {
    StringBuffer sb = null;

    try {
      sb = getAuction(item_id);
      if(sb != null && ae != null) {
        ae.clearDeleted();
      }
    } catch (FileNotFoundException ignored) {
      //  Just get out.  The item no longer exists on the auction
      //  server, so we shouldn't be trying any of the rest.  The
      //  Error should have been logged at the lower level, so just
      //  punt.  It's not a communications error, either.
      markAuctionDeleted(ae);
    } catch (Exception catchall) {
      if (JConfig.debugging()) {
        JConfig.log().handleException("Some unexpected error occurred during loading the auction.", catchall);
      }
    }

    return sb;
  }

  public SpecificAuction doParse(StringBuffer sb) throws ReloadItemException {
    return doParse(sb, null, null);
  }

  private SpecificAuction doParse(StringBuffer sb, AuctionEntry ae, String item_id) throws ReloadItemException {
    SpecificAuction curAuction = getNewSpecificAuction();

    if (item_id != null) {
      curAuction.setIdentifier(item_id);
    } else if(ae != null && ae.getIdentifier() != null) {
      curAuction.setIdentifier(ae.getIdentifier());
    }
    curAuction.setContent(sb, false);
    String error = null;
    SpecificAuction.ParseErrors result = null;
    if (curAuction.preParseAuction()) {
      result = curAuction.parseAuction(ae);
      if (result != SpecificAuction.ParseErrors.SUCCESS) {
        switch(result) {
          case WRONG_SITE: {
            String rightURL = curAuction.getURL();
            JConfig.log().logDebug("Need to redirect to: " + rightURL);
            JConfig.log().logMessage("Attempted to read an auction that is not available on the default site; check eBay's non-US configuration.");
            return null;
          }
          case CAPTCHA: {
            JConfig.log().logDebug("Failed to load (likely adult) item, captcha intervened.");
            if(ae != null) {
              ae.setLastStatus("Couldn't access auction on server; captcha blocked.");
            }
            break;
          }
          case NOT_ADULT: {
            boolean isAdult = JConfig.queryConfiguration(getName() + ".mature", "false").equals("true");
            if (isAdult) {
              getNecessaryCookie(true);
              throw new ReloadItemException();
            } else {
              JConfig.log().logDebug("Failed to load adult item, user possibly not marked for Mature Items access.  Check your eBay configuration.");
            }
            break;
          }
          case DELETED: {
            error = markAuctionDeleted(ae);
            break;
          }
          case SELLER_AWAY: {
            error = "Seller away - item unavailable.";
            break;
          }
          case BAD_TITLE: {
            error = "There was a problem parsing the title.";
            break;
          }
        }
        if(result != SpecificAuction.ParseErrors.SUCCESS && error == null) {
          error = "Bad Parse!";
        }
      }
      if (result == SpecificAuction.ParseErrors.SUCCESS) {
        curAuction.save();
      }
    } else {
      error = "Bad pre-parse!";
    }

    if(error != null) {
      JConfig.log().logMessage(error);
      if(ae == null || !ae.isDeleted() && result != SpecificAuction.ParseErrors.SELLER_AWAY) {
        checkLogError(ae);
      }
      curAuction = null;
    }
    return curAuction;
  }

  private String markAuctionDeleted(AuctionEntry ae) {
    String error = "Auction appears to have been removed from the site.";
    if(ae != null) {
      ae.setDeleted();
      error = "Auction " + ae.getIdentifier() + " appears to have been removed from the site.";
      ae.setLastStatus(error);
    }
    return error;
  }

  private void noteRetrieveError(AuctionEntry ae) {
    checkLogError(ae);
    //  Whoops!  Bad thing happened on the way to loading the auction!
    JConfig.log().logDebug("Failed to parse auction!  Bad return result from auction server.");
    //  Only retry the login cookie once every ten minutes of these errors.
    if ((sLastUpdated + Constants.ONE_MINUTE * 10) > System.currentTimeMillis()) {
      sLastUpdated = System.currentTimeMillis();
      MQFactory.getConcrete(this.getFriendlyName()).enqueueBean(new AuctionQObject(AuctionQObject.MENU_CMD, UPDATE_LOGIN_COOKIE, null)); //$NON-NLS-1$ //$NON-NLS-2$
    }
  }

  /**
   * If we had an auction entry, note the failure on it's record.
   * Otherwise, note a general communications failure.
   *
   * @param ae - The optional auction entry.
   */
  private void checkLogError(AuctionEntry ae) {
    if (ae != null) {
      ae.logError();
    } else {
      MQFactory.getConcrete("Swing").enqueue("LINK DOWN Communications failure talking to the server");
    }
  }

  protected abstract String getUserId();

  /**
   * Check to see if the provided user name is the current app user.
   *
   * @param username - The username to check.
   * @return - false if username is null, or if the current user is the 'default' user, or if the username provided is different
   * than the current username.  True if the current app user is the same as the username passed in.
   */
  public boolean isCurrentUser(String username) {
    return !(username == null || isDefaultUser()) && getUserId().trim().equalsIgnoreCase(username.trim());
  }
}
TOP

Related Classes of com.jbidwatcher.auction.server.AuctionServer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.