/* * [DemoIsASINInStock.java] * * Summary: Find out if a given ISBN/ASIN is in stock using AWS API. D E M O C O D E. * * Copyright: (c) 2012-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2012-03-26 initial version */ package com.mindprod.aws; import com.mindprod.aws.jax.AWSECommerceService; import com.mindprod.aws.jax.AWSECommerceServicePortType; import com.mindprod.aws.jax.AwsHandlerResolver; import com.mindprod.aws.jax.Item; import com.mindprod.aws.jax.ItemLookup; import com.mindprod.aws.jax.ItemLookupRequest; import com.mindprod.aws.jax.Items; import com.mindprod.aws.jax.Offer; import com.mindprod.aws.jax.OfferListing; import com.mindprod.aws.jax.OperationRequest; import com.mindprod.isbn.ISBNValidate; import javax.xml.namespace.QName; import javax.xml.ws.Holder; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import static java.lang.System.*; /** * Find out if a given ISBN/ASIN is in stock using AWS API. D E M O C O D E. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2012-03-26 initial version * @see com.mindprod.aws.FetchBookFacts * @see PobeViaAWS#isASINInStockViaAWS * @since 2012-03-26 */ public class DemoIsASINInStock { /** * true if debugging, and want extra output */ private static final boolean DEBUGGING = false; /** * true if probe amazon.ca , false amazon.com. Surprisingly this is only referenced twice in the program. */ private static final boolean IS_CANADIAN = true; /** * fetch public amazon.com-assigned associateTag from environment set awsassociatetag=xxxxx */ private static final String ASSOCIATE_TAG = IS_CANADIAN ? System.getenv( "awsassociatetagca" ) : System.getenv( "awsassociatetag" ); /** * fetch confidential amazon.com-assigned awsAccessKeyId from environment set awsaccesskeyid=xxxxx */ private static final String AWS_ACCESS_KEY_ID = System.getenv( "awsaccesskeyid" ); /** * fetch confidential amazon.com-assigned awsSecretAccessKey assigned by Amazon set awssecretaccesskey=xxxxx */ private static final String AWS_SECRET_ACCESS_KEY = System.getenv( "awssecretaccesskey" ); /** * identifies the context in which names should be interpreted in the schema. * Why do we need to specify this? It appears FOUR times in the wsdl file. Perhaps as a check the code * matches the generated Java. */ private static final String NAME_SPACE_URI = "http://webservices.amazon.com/AWSECommerceService/2013-08-01"; /** * name of the SOAP service */ private static final String QNAME = "AWSECommerceService"; /** * location of JAX schmo, locally cached. for amazon.com in the USA. Would have to be modified for other countries. * Original came from http://ecs.amazonaws.com/AWSECommerceService/AWSECommerceService.wsd * Both Amazon.ca and Amazon.com use the same WSDL. */ private static final String WSDL_LOCATION = "file:///E:/com/mindprod/aws/jax/AWSECommerceService.wsdl"; /** * standard boilerplate to connect to amazon.com AWS server with SOAP * * @return port to use to send requests. * @throws java.net.MalformedURLException if some URLs were mis-specified in the following code. */ private static AWSECommerceServicePortType getPort() throws MalformedURLException { // Set the service: AWSECommerceService service = new AWSECommerceService( new URL( WSDL_LOCATION ), new QName( NAME_SPACE_URI, QNAME ) ); // AwsHandlerResolver does the timestamp, signing and Base64 encoding service.setHandlerResolver( new AwsHandlerResolver( AWS_SECRET_ACCESS_KEY ) ); // get the corresponding service port. This looks up the endpoint server. return IS_CANADIAN ? service.getAWSECommerceServicePortCA() : service.getAWSECommerceServicePort(); } /** * probe the amazon AWS api to find if a given asin is in stock. * * @param asin Amazon part number * * @return true if product is in stock. * @throws java.net.MalformedURLException if generated URL is malformed */ private static boolean isAsinInStock( final String asin ) throws MalformedURLException { final AWSECommerceServicePortType port = getPort(); // new ItemLookup final ItemLookup itemLookup = new ItemLookup(); // new ItemLookupRequest which is part of the ItemLookup final ItemLookupRequest itemLookupRequest = new ItemLookupRequest(); // odd our lookup request to the the Lookup. final List itemLookupRequests = itemLookup.getRequest(); itemLookupRequests.add( itemLookupRequest ); // Set up the values of the ItemLookupRequest // lookup of variants only works with ASIN itemLookupRequest.setIdType( "ASIN" ); itemLookupRequest.getItemId().add( asin ); // there is no setItemID method itemLookupRequest.setMerchantId( "All" ); itemLookupRequest.setCondition( "All" ); // specify info to include in response final List responseGroup = itemLookupRequest.getResponseGroup(); responseGroup.add( "Offers" ); // set up Holder for the response tree final Holder operationRequest = new Holder<>(); final Holder> items = new Holder<>(); final String marketplaceDomain = ""; // not yet supported final String xmlEscaping = "Single"; final String validate = ""; // Probe Amazon Server, WARNING! Amazon changes the parms to this method frequently. // Inserts awsAccessKeyID and associateTag // note order validate, xmlEscaping, different from itemSearch port.itemLookup( marketplaceDomain, AWS_ACCESS_KEY_ID, ASSOCIATE_TAG, validate, xmlEscaping, itemLookupRequest, itemLookupRequests, operationRequest, items ); // analyse results final List result = items.value; final int size = result.get( 0 ).getItem().size(); for ( int i = 0; i < size; i++ ) { final Item item = result.get( 0 ).getItem().get( i ); for ( Offer offer : item.getOffers().getOffer() ) { for ( OfferListing offerListing : offer.getOfferListing() ) { final String availabilityType = offerListing.getAvailabilityAttributes().getAvailabilityType(); if ( true ) { // might be "now" or "unknown" (temp out of stock) or "futureDate" out.println( "asin = " + asin + " availabilityType = " + availabilityType ); } if ( availabilityType.equals( "now" ) ) { return true; } } } } //end loop to process results return false; } /** * convert isbn13 to asin * * @param isbn13 isbn13 * * @return corresponding asin, if no match, returns null. * @throws java.net.MalformedURLException if generated URL is malformed. */ private static String isbnToAsin( final String isbn13 ) throws MalformedURLException { // for amazon.com in USA // define magic configuring strings final AWSECommerceServicePortType port = getPort(); // new ItemLookup final ItemLookup itemLookup = new ItemLookup(); // new ItemLookupRequest which is part of the ItemLookup final ItemLookupRequest itemLookupRequest = new ItemLookupRequest(); // odd our lookup request to the the Lookup. final List itemLookupRequests = itemLookup.getRequest(); itemLookupRequests.add( itemLookupRequest ); // Set up the values of the ItemLookupRequest itemLookupRequest.setSearchIndex( "Books" ); itemLookupRequest.setIdType( "EAN" ); itemLookupRequest.getItemId().add( isbn13 ); // there is no setItemID method itemLookupRequest.setMerchantId( "All" ); itemLookupRequest.setCondition( "All" ); // specify info to include in response final List responseGroup = itemLookupRequest.getResponseGroup(); responseGroup.add( "ItemAttributes" ); // set up Holder for the response tree final Holder operationrequest = new Holder<>(); final Holder> items = new Holder<>(); final String marketplaceDomain = ""; // not yet supported final String xmlEscaping = "Single"; final String validate = ""; // Probe Amazon Server, WARNING! Amazon changes the parms to this method frequently. // Inserts awsAccessKeyID and associateTag // note order validate, xmlEscaping, different from itemSearch port.itemLookup( marketplaceDomain, AWS_ACCESS_KEY_ID, ASSOCIATE_TAG, validate, xmlEscaping, itemLookupRequest, itemLookupRequests, operationrequest, items ); // analyse results final List result = items.value; final int size = result.get( 0 ).getItem().size(); for ( int i = 0; i < size; i++ ) { final Item item = result.get( 0 ).getItem().get( i ); final String asin = item.getASIN(); if ( asin != null ) { return asin; } } //end loop to process results return null; } /** * Probe the amazon AWS api for isbn13 or asin to find out if instock. * Gives extremely inaccurate results compared with going to the website. * Probes US website. * * @param args list of isbn13/asins to probe. * * @throws java.io.IOException if trouble reading/writing files */ public static void main( String[] args ) throws IOException { if ( DEBUGGING ) { out.println( "ASSOCIATE_TAG = " + ASSOCIATE_TAG ); out.println( "AWS_ACCESS_KEY_ID = " + AWS_ACCESS_KEY_ID ); out.println( "AWS_SECRET_ACCESS_KEY = " + AWS_SECRET_ACCESS_KEY ); } for ( String arg : args ) { if ( arg.length() == 13 ) { final String isbn13 = ISBNValidate.tidyISBN10or13RemovingDashes( arg ); final String asin = isbnToAsin( isbn13 ); if ( asin == null ) { err.println( isbn13 + " is has no valid asin" ); } else { final boolean inStock = isAsinInStock( asin ); out.println( "isbn13: " + arg + " asin: " + asin + " " + inStock ); } } else { final boolean inStock = isAsinInStock( arg ); out.println( "asin: " + arg + " " + inStock ); } } } }